Java類執行順序


一、先來了解幾個概念

1、靜態代碼塊

     (1)格式

          在java類中(方法中不能存在靜態代碼塊)使用static關鍵字和{}聲明的代碼塊

public class CodeBlock { static{ System.out.println("靜態代碼塊"); } }

  (2)執行時機

            靜態代碼塊在類被加載的時候就運行了,而且只運行一次,並且優先於各種代碼塊以及構造函數。如果一個類中有多個靜態代碼塊,會按照書寫順序依次執行。后面在比較的時候會通過具體實例來證明。

 (3)靜態代碼塊的作用

        一般情況下,如果有些代碼需要在項目啟動的時候就執行,這時候就需要靜態代碼塊。比如一個項目啟動需要加載的很多配置文件等資源,我們就可以都放入靜態代碼塊中。

 (4)靜態代碼塊不能存在任何方法體中

       首先我們要明確靜態代碼塊是在類加載的時候就要運行了。我們分情況討論:

  •  對於普通方法:由於普通方法是通過加載類,然后new出實例化對象,通過對象才能運行這個方法,而靜態代碼塊只需要加載類之后就能運行了。
  •  對於靜態方法:在類加載的時候,靜態方法也已經加載了,但是我們必須要通過類名或者對象名才能訪問,也就是說相比於靜態代碼塊,靜態代碼塊是主動運行的,而靜態方法是被動運行的。

 (5)靜態代碼塊不能訪問普通變量

        普通變量只能通過對象來調用,是不能放在靜態代碼塊中的。

2、構造代碼塊

       (1)格式

            在java類中使用{}聲明的代碼塊(和靜態代碼塊的區別是少了static關鍵字):

public class CodeBlock { static{ System.out.println("靜態代碼塊"); } { System.out.println("構造代碼塊"); } }

 (2)執行時機

            構造代碼塊在創建對象時被調用,每次創建對象都會調用一次,但是優先於構造函數執行。

      但是要明白:構造代碼塊依托於構造函數,也就是說,如果你不實例化對象,構造代碼塊是不會執行的

public class Constructor { { System.out.println("構造代碼塊"); } public Constructor(){ System.out.println("無參構造函數"); } public Constructor(String str){ System.out.println("有參構造函數"); } public static void main(String[] args) { new Constructor(); System.out.println(); new Constructor("構造代碼塊"); } }

   

   (3)構造代碼塊的作用

      和構造函數的作用類似,都能對對象進行初始化,並且只要創建一個對象,構造代碼塊都會執行一次

           反過來,構造函數則不一定每個對象建立時都執行(多個構造函數情況下,建立對象時,傳入的參數不同則初始化使用對應的構造函數)。

3、構造函數

  (1)構造函數的命名必須和類名完全相同。在java中普通函數可以和構造函數同名,但是必須帶有返回值;

  (2)構造函數的功能主要用於在類的對象創建時定義初始化的狀態。它沒有返回值,也不能用void來修飾。這就保證了它不僅什么也不用自動返回,而且根本不能有任何選擇。而其他方法都有返回值,即使是void返回值。

  (3)構造函數不能被直接調用,必須通過new運算符在創建對象時才會自動調用;而一般的方法是在程序執行到它的時候被調用的;

  (4)默認先調用父類的無參構造函數

4、普通代碼塊

  普通代碼塊和構造代碼塊的區別是

  •       構造代碼塊是在類中定義的,
  •       普通代碼塊是在方法體中定義的。且普通代碼塊的執行順序和書寫順序一致。
public void sayHello(){ { System.out.println("普通代碼塊"); } }

5、各種類型變量的默認初始值

  JVM 類加載機制中提到,類連接 (驗證, 准備, 解析)中准備工作:

    負責為類的類變量(非對象變量)分配內存,並設置默認初始值,准備類中每個字段、方法和實現接口所需的數據結構

    這里說的初始值都是默認的值, 並不是程序中指定的值 :看例子

public class Text { public static int k = 10; public int a = print("a"); public static int b = print("b"); public static Text t1 = new Text("t1"); public static Text t2 = new Text("t2"); public static int i = print("i"); public static int n = 99; public int j = print("j"); }

  經過准備工作后,類中變量的初始值為如下

       k =0;     b=0;     t1=null;     t2=null;    i=0;    n=0;

  

二、正題:Java的實例化順序

1、牢記:靜態和非靜態分開處理

 (1)使用到靜態加載時,靜態又分為: 靜態變量, 靜態代碼塊,其中加載順序是按照類中書寫的先后順序加載的
 (2)非靜態加載順序: 按照非靜態書寫順序加載  /()執行
 (3)靜態方法,實例方法只有在調用的時候才會去執行
 (4)當靜態加載中遇到需要加載非靜態的情況: 先加載非靜態再加載靜態(因為非靜態可以訪問靜態,而靜態不能訪問非靜態)

public static Text t1 = new Text("t1"); // 當加載靜態變量是需要先加載構造器, 那就轉為先加載所有非靜態屬性

2、靜態變量聲明   一定  放在使用前面

     

3、main是否第一句先執行

  Java程序運行時,第一件事情就是試圖訪問main方法,因為main相等於程序的入口,如果沒有main方法,程序將無法啟動,main方法更是占一個獨立的線程,找到main方法后,是不是就會執行mian方法塊里的第一句話呢?

  答:不是

    因為main方法雖然是一個特殊的靜態方法,但是還是靜態方法,此時JVM會加載main方法所在的類,試圖找到類中其他靜態部分,即首先會找main方法所在的類。

public class JVMTest { static{ System.out.println("Main 方法所在靜態代碼塊 static1"); } public static void main(String[] args) { System.out.println("main start"); A a = new A(); System.out.println(A.width); System.out.println(a.width); } static{ System.out.println("Main 方法所在靜態代碼塊 static2"); } } class A{ public static int width = 100; static{ System.out.println("靜態初始化類A"); width = 30; } public A(){ System.out.println("創建A類的對象"); } }

4、父類、子類加載順序

/* * 父類 */
public class JVMParent { public static int width = 100; public static int count; { System.out.println("parent no static code block :" + count); } static{ System.out.println("parent static's count:" + count); } JVMParent(int a){ System.out.println("parent init one parameter"); } JVMParent(){ System.out.println("parent init"); } }

 

/* * 子類 */
public class JVMSons extends JVMParent { { System.out.println("son no static code block :" + count); } static { System.out.println("son static 1"); } public static int count1; JVMSons() { System.out.println("son init:" + count); } static { System.out.println("son static 2"); } public static void main(String[] args) { System.out.println("son main start"); JVMSons a = new JVMSons(); } }

   先自己分析一下,然后看總結。

5、總結 

  1、父類的靜態變量和靜態塊賦值(按照聲明順序)
  2、自身的靜態變量和靜態塊賦值(按照聲明順序)
  3、main方法
  3、父類的成員變量和塊賦值(按照聲明順序)
  4、父類構造器賦值
  5、自身成員變量和塊賦值(按照聲明順序)
  6、自身構造器賦值
  7、靜態方法,實例方法只有在調用的時候才會去執行

 

三、參考

        https://www.cnblogs.com/zhongHW/p/11047007.html

        https://www.cnblogs.com/UncleWang001/articles/10429801.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM