摘要:沒有關鍵字修飾的如實例變量非靜態(tài)變量非靜態(tài)代碼塊初始化實際上是會被提取到類的構造器中被執(zhí)行的,但是會比類構造器中的代碼塊優(yōu)先執(zhí)行到,非靜態(tài)實例變量非靜態(tài)代碼塊的地位是相等的,它們將按順序被執(zhí)行。
閱讀原文:Java代碼執(zhí)行順序
程序中代碼執(zhí)行的順序非常重要,稍有不慎便會是程序運行出錯,那么我將結合實例來分析代碼中的執(zhí)行。
名詞解釋首先了解幾個名詞:
非靜態(tài)代碼塊直接由 { } 包起來的代碼,稱為非靜態(tài)代碼塊靜態(tài)代碼塊
直接由 static { } 包起來的代碼,稱為靜態(tài)代碼塊形參
比如你定義一個函數(shù)void add(int a, int b),這里的a和b就是形參。
當你進行函數(shù)調(diào)用的時候,add(1, 2),這里的1和2就是實參。
所謂向前引用,就是在定義類、接口、方法、變量之前使用它們。
成員變量在類體里面定義的變量稱為成員變量; 如果該成員變量有 static 關鍵字修飾,則該成員變量稱為 靜態(tài)變量 或 類變量; 如果該成員變量沒有 static 關鍵字修飾,則該成員變量被稱為 非靜態(tài)變量 或 實例變量。局部變量
形參、方法內(nèi)定義的變量、代碼塊中定義的變量,都屬于局部變量。類變量 (靜態(tài)變量)
可以向前引用 變量屬于類本身 類變量不依賴類的實例,類變量只在初始化時候在方法區(qū)中被分配一次空間,無論類的實例被創(chuàng)建幾次,都不再為類變量分配空間 通過類的任意一個實例來訪問類變量,底層都將將其轉(zhuǎn)為通過類本身來訪問類變量,它們的效果是一樣的 一旦類變量的值被改變,通過類或類的任意一個實例來訪問類變量,得到的都將是被改變后的值 將在類的初始化之前初始化實例變量(非靜態(tài)變量)
不能向前引用,如果向前引用,則稱為非法向前引用,這是不允許的 變量屬于類的實例對象 隨著類的實例被創(chuàng)建而分配內(nèi)存空間實例演示
public class Parent { public int parentNum=0; public static int staticParentNum=0; { System.out.println("Parent---執(zhí)行非靜態(tài)代碼塊了1!"); } { System.out.println("Parent---執(zhí)行非靜態(tài)代碼塊了2!"); } static{ System.out.println("Parent---執(zhí)行靜態(tài)代碼塊了1!"); } static{ System.out.println("Parent---執(zhí)行靜態(tài)代碼塊了2!"); } public Parent(){ System.out.println("Parent---無參構造函數(shù)!"); } public Parent(int parentNum){ this.parentNum=parentNum; System.out.println("Parent---有參構造函數(shù)!"); } public void ParentMethod(int parentNum){ this.parentNum=parentNum; System.out.println("Parent---非靜態(tài)方法/parentNum="+parentNum); } public static void staticParentMethod(int staticParentNum){ Parent.staticParentNum=staticParentNum; System.out.println("Parent---靜態(tài)方法/staticParentNum="+staticParentNum); } }
public class Child extends Parent{ public int childNum=0; public static int staticChildNum=0; { System.out.println("Child---執(zhí)行非靜態(tài)代碼塊了1!"); } { System.out.println("Child---執(zhí)行非靜態(tài)代碼塊了2!"); } static{ System.out.println("Child---執(zhí)行靜態(tài)代碼塊了1!"); } static{ System.out.println("Child---執(zhí)行靜態(tài)代碼塊了2!"); } public Child(){ super(); System.out.println("Child---無參構造函數(shù)!"); } public Child(int childNum){ super(childNum); System.out.println("Child---有參構造函數(shù)!"); } public void childMethod(int childNum){ this.childNum=childNum; System.out.println("Child--非靜態(tài)方法/childNum="+childNum); } public static void staticChildMethod(int staticChildNum){ Child.staticChildNum=staticChildNum; System.out.println("Child---靜態(tài)方法/staticChildNum="+staticChildNum); } }
package test; public class Test { // static{ // System.out.println("Test---靜態(tài)代碼塊!"); // } public static void main(String[] args) { int key=10; switch (key) { case 0: Parent parent=new Parent(); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Parent---執(zhí)行非靜態(tài)代碼塊了1! // Parent---執(zhí)行非靜態(tài)代碼塊了2! // Parent---無參構造函數(shù)! // 說明:先加載靜態(tài)代碼塊,后加載非靜態(tài)代碼塊 case 1: Child b= new Child(); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Child---執(zhí)行靜態(tài)代碼塊了1! // Child---執(zhí)行靜態(tài)代碼塊了2! // Parent---執(zhí)行非靜態(tài)代碼塊了1! // Parent---執(zhí)行非靜態(tài)代碼塊了2! // Parent---無參構造函數(shù)! // Child---執(zhí)行非靜態(tài)代碼塊了1! // Child---執(zhí)行非靜態(tài)代碼塊了2! // Child---無參構造函數(shù)! // 說明:創(chuàng)建子類,會先執(zhí)行父類,先執(zhí)行父類靜態(tài)——>子類靜態(tài)——>父類非靜態(tài)——>父類構造 //——>子類非靜態(tài)——>子類構造 case 2: Child c= new Child(4); //這個構造函數(shù)中指明了調(diào)用父類的有參構造函數(shù),若不指定,則調(diào)用父類無參構造函數(shù) break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Child---執(zhí)行靜態(tài)代碼塊了1! // Child---執(zhí)行靜態(tài)代碼塊了2! // Parent---執(zhí)行非靜態(tài)代碼塊了1! // Parent---執(zhí)行非靜態(tài)代碼塊了2! // Parent---有參構造函數(shù)! // Child---執(zhí)行非靜態(tài)代碼塊了1! // Child---執(zhí)行非靜態(tài)代碼塊了2! // Child---有參構造函數(shù)! 說明:靜態(tài)代碼塊或非靜態(tài)代碼塊執(zhí)行順序,按照代碼前后編寫順序。 case 3: Child d= new Child(); Child e= new Child(4); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Child---執(zhí)行靜態(tài)代碼塊了1! // Child---執(zhí)行靜態(tài)代碼塊了2! // Parent---執(zhí)行非靜態(tài)代碼塊了1! // Parent---執(zhí)行非靜態(tài)代碼塊了2! // Parent---無參構造函數(shù)! // Child---執(zhí)行非靜態(tài)代碼塊了1! // Child---執(zhí)行非靜態(tài)代碼塊了2! // Child---無參構造函數(shù)! // Parent---執(zhí)行非靜態(tài)代碼塊了1! // Parent---執(zhí)行非靜態(tài)代碼塊了2! // Parent---有參構造函數(shù)! // Child---執(zhí)行非靜態(tài)代碼塊了1! // Child---執(zhí)行非靜態(tài)代碼塊了2! // Child---有參構造函數(shù)! 說明:創(chuàng)建多個子類,但父類靜態(tài)代碼塊只執(zhí)行一次。 case 4: Child.staticChildMethod(4); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Child---執(zhí)行靜態(tài)代碼塊了1! // Child---執(zhí)行靜態(tài)代碼塊了2! // Child---靜態(tài)方法/staticChildNum=4 說明:靜態(tài)方法只可以調(diào)用靜態(tài)變量。 case 5: Parent.staticParentMethod(5); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Parent---靜態(tài)方法/staticParentNum=5 說明:靜態(tài)方法可通過 父類名.靜態(tài)方法() 調(diào)用。 case 6: System.out.println("父類的靜態(tài)變量值staticParentNum="+Parent.staticParentNum); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // 父類的靜態(tài)變量值staticParentNum=0 說明:調(diào)用靜態(tài)變量時,靜態(tài)代碼塊會執(zhí)行。 case 7: System.out.println("子類的靜態(tài)變量值staticChildNum="+Child.staticChildNum); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Child---執(zhí)行靜態(tài)代碼塊了1! // Child---執(zhí)行靜態(tài)代碼塊了2! // 子類的靜態(tài)變量值staticChildNum=0 說明:調(diào)用子類靜態(tài)變量,父類靜態(tài)代碼塊和子類靜態(tài)代碼塊會被執(zhí)行。 case 8: System.out.println("父類的靜態(tài)變量值staticParentNum="+Parent.staticParentNum); System.out.println("子類的靜態(tài)變量值staticChildNum="+Child.staticChildNum); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // 父類的靜態(tài)變量值staticParentNum=0 // Child---執(zhí)行靜態(tài)代碼塊了1! // Child---執(zhí)行靜態(tài)代碼塊了2! // 子類的靜態(tài)變量值staticChildNum=0 case 9: Child f= new Child(); f.ParentMethod(3); break; // Parent---執(zhí)行靜態(tài)代碼塊了1! // Parent---執(zhí)行靜態(tài)代碼塊了2! // Child---執(zhí)行靜態(tài)代碼塊了1! // Child---執(zhí)行靜態(tài)代碼塊了2! // Parent---執(zhí)行非靜態(tài)代碼塊了1! // Parent---執(zhí)行非靜態(tài)代碼塊了2! // Parent---無參構造函數(shù)! // Child---執(zhí)行非靜態(tài)代碼塊了1! // Child---執(zhí)行非靜態(tài)代碼塊了2! // Child---無參構造函數(shù)! // Parent---非靜態(tài)方法/parentNum=3 說明:創(chuàng)建子類,用子類調(diào)用父類方法,非靜態(tài)方法可以調(diào)用靜態(tài)變量。 default: break; } } }總結
Java代碼初始化順序
由 static 關鍵字修飾的(如:類變量(靜態(tài)變量)、靜態(tài)代碼塊)將在類被初始化創(chuàng)建實例對象之前被初始化,而且是按順序從上到下依次被執(zhí)行。靜態(tài)(類變量、靜態(tài)代碼塊)屬于類本身,不依賴于類的實例。
沒有 static 關鍵字修飾的(如:實例變量(非靜態(tài)變量)、非靜態(tài)代碼塊)初始化實際上是會被提取到類的構造器中被執(zhí)行的,但是會比類構造器中的代碼塊優(yōu)先執(zhí)行到,非靜態(tài)(實例變量、非靜態(tài)代碼塊)的地位是相等的,它們將按順序被執(zhí)行。
類變量(靜態(tài)變量)、實例變量(非靜態(tài)變量)、靜態(tài)代碼塊、非靜態(tài)代碼塊的初始化時機
由 static 關鍵字修飾的(如:類變量[靜態(tài)變量]、靜態(tài)代碼塊)將在類被初始化創(chuàng)建實例對象之前被初始化,而且是按順序從上到下依次被執(zhí)行;
沒有 static 關鍵字修飾的(如:實例變量[非靜態(tài)變量]、非靜態(tài)代碼塊)初始化實際上是會被提取到類的構造器中被執(zhí)行的,但是會比類構造器中的 代碼塊優(yōu)先執(zhí)行到,其也是按順序從上到下依次被執(zhí)行。
容易混淆的一個知識點
靜態(tài)方法只允許直接訪問靜態(tài)成員,而實例方法中可以訪問靜態(tài)成員和實例成員,原因是類還沒有實例化,所實例成員也沒有被創(chuàng)建,靜態(tài)方法中因此也不能用this。
歡迎關注公眾號交流!
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/73700.html
摘要:并發(fā)編程的挑戰(zhàn)并發(fā)編程的目的是為了讓程序運行的更快,但是,并不是啟動更多的線程就能讓程序最大限度的并發(fā)執(zhí)行。的實現(xiàn)原理與應用在多線程并發(fā)編程中一直是元老級角色,很多人都會稱呼它為重量級鎖。 并發(fā)編程的挑戰(zhàn) 并發(fā)編程的目的是為了讓程序運行的更快,但是,并不是啟動更多的線程就能讓程序最大限度的并發(fā)執(zhí)行。如果希望通過多線程執(zhí)行任務讓程序運行的更快,會面臨非常多的挑戰(zhàn):(1)上下文切換(2)死...
摘要:下面是該程序在兩個內(nèi)存模型中的執(zhí)行時序?qū)Ρ葓D在順序一致性模型中,所有操作完全按程序的順序串行執(zhí)行。不保證未同步程序的執(zhí)行結果與該程序在順序一致性模型中的執(zhí)行結果一致。 前情提要 深入理解Java內(nèi)存模型(二)——重排序 數(shù)據(jù)競爭與順序一致性保證 當程序未正確同步時,就會存在數(shù)據(jù)競爭。java內(nèi)存模型規(guī)范對數(shù)據(jù)競爭的定義如下: 在一個線程中寫一個變量, 在另一個線程讀同一個變量,...
摘要:前提深入理解內(nèi)存模型程曉明著,該書在以前看過一遍,現(xiàn)在學的東西越多,感覺那塊越重要,于是又再細看一遍,于是便有了下面的讀書筆記總結。同步同步是指程序用于控制不同線程之間操作發(fā)生相對順序的機制。線程之間的通信由內(nèi)存模型控制。 showImg(https://segmentfault.com/img/remote/1460000013474312?w=1920&h=1271); 前提 《深...
摘要:前提深入理解內(nèi)存模型程曉明著,該書在以前看過一遍,現(xiàn)在學的東西越多,感覺那塊越重要,于是又再細看一遍,于是便有了下面的讀書筆記總結。同步同步是指程序用于控制不同線程之間操作發(fā)生相對順序的機制。線程之間的通信由內(nèi)存模型控制。 showImg(https://mmbiz.qpic.cn/mmbiz_jpg/1flHOHZw6RtPu3BNx3zps1JhSmPICRw7QgeOmxOfTb...
摘要:并發(fā)編程關鍵字解析解析概覽內(nèi)存模型的相關概念并發(fā)編程中的三個概念內(nèi)存模型深入剖析關鍵字使用關鍵字的場景內(nèi)存模型的相關概念緩存一致性問題。事實上,這個規(guī)則是用來保證程序在單線程中執(zhí)行結果的正確性,但無法保證程序在多線程中執(zhí)行的正確性。 Java并發(fā)編程:volatile關鍵字解析 1、解析概覽 內(nèi)存模型的相關概念 并發(fā)編程中的三個概念 Java內(nèi)存模型 深入剖析volatile關鍵字 ...
摘要:前情提要深入理解內(nèi)存模型一基礎編譯器運行時會對指令進行重排序。以處理器的猜測執(zhí)行為例,執(zhí)行線程的處理器可以提前讀取并計算,然后把計算結果臨時保存到一個名為重排序緩沖的硬件緩存中。請看下篇深入理解內(nèi)存模型三順序一致性 前情提要 深入理解Java內(nèi)存模型(一)——基礎 Java編譯器、運行時會對指令進行重排序。這種重排序在單線程和多線程情況下分別有什么影響呢? 數(shù)據(jù)依賴性 如果兩個操...
閱讀 976·2021-09-27 13:36
閱讀 954·2021-09-08 09:35
閱讀 1102·2021-08-12 13:25
閱讀 1467·2019-08-29 16:52
閱讀 2939·2019-08-29 15:12
閱讀 2757·2019-08-29 14:17
閱讀 2652·2019-08-26 13:57
閱讀 1042·2019-08-26 13:51