Java 對象的初始化過程_上
- 2020 年 3 月 11 日
- 筆記
前言
本文主要以白話的形式 『簡單』 的描述在 java 中 new 對象的過程,之所以說是 『簡單』 的描述是因為,在本文中不會講述底層的載入過程。
示例
首先認識幾個知識點:
- 靜態程式碼塊 它會在類初始化的時候執行一次,僅能初始化類變數, 即被static修飾的成員變數,如果有多個靜態程式碼塊時,會按照靜態程式碼塊的編寫順序執行。實際上編譯後多個靜態程式碼塊中的程式碼,會按編寫時的順序整合到一個靜態程式碼塊。
- 構造程式碼塊 實際上源程式碼在被編譯後,構造程式碼塊中的程式碼就會被複制移動到構造方法程式碼的前面,也就會隨著構造方法的運行而運行。如果存有多個構造方法時,將會在每個構造方法的程式碼之前都放置一遍 構造程式碼塊中的程式碼 。所以也可以認為,構造程式碼塊將在構造方法執行之前執行,如果存在有多個構造程式碼塊時,那麼就會按照構造程式碼塊的編寫順序執行。由於構造程式碼塊的程式碼是放到構造方法中執行的,所以作用也是初始化類實例變數。適用場景:
- 一個類,它不管創建多少個實例對象,都需要執行相同的初始化程式碼。
- 你的類有n個構造方法,而每個構造方法都需要執行相同的初始化程式碼。
- 構造方法 構造方法將會在類實例化時執行,也就是在被 new 時執行,需要注意的是,構造方法可以存在多個,如果你沒有顯示聲明,一個沒寫的話,那編譯器就會幫你加一個默認的構造方法。構造方法可以初始化類成員變數。
知道以上三個知識點後,那麼就先創建一個Person類,觀察一下
Person.java
package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; static { System.out.println("靜態程式碼塊1"); } { System.out.println("構造程式碼塊1"); } static { System.out.println("靜態程式碼塊2"); } { System.out.println("構造程式碼塊2"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
對其編譯,使用IDEA的反編譯功能查看class文件內容
Person.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; public Person() { System.out.println("構造程式碼塊1"); System.out.println("構造程式碼塊2"); } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } public String getSex() { return this.sex; } public void setSex(String sex) { this.sex = sex; } static { System.out.println("靜態程式碼塊1"); System.out.println("靜態程式碼塊2"); } }
首先觀察到,編譯後的程式碼,和咱寫的程式碼有點區別:
- 編譯器自動幫我曾加了一個默認的,空參數的構造函數。
- 編譯器刪除了構造程式碼塊,並將被刪除的構造程式碼塊中的程式碼,有序的放置到了構造方法中。
下面再在Person類中,顯示聲明多個構造函數。
Person.java
package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; static { System.out.println("靜態程式碼塊1"); } { System.out.println("構造程式碼塊1"); } public Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } public Person(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } static { System.out.println("靜態程式碼塊2"); } { System.out.println("構造程式碼塊2"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
查看編譯後的內容
Person.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; public Person(String name) { System.out.println("構造程式碼塊1"); System.out.println("構造程式碼塊2"); this.name = name; } public Person(String name, int age) { System.out.println("構造程式碼塊1"); System.out.println("構造程式碼塊2"); this.name = name; this.age = age; } public Person(String name, int age, String sex) { System.out.println("構造程式碼塊1"); System.out.println("構造程式碼塊2"); this.name = name; this.age = age; this.sex = sex; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } public String getSex() { return this.sex; } public void setSex(String sex) { this.sex = sex; } static { System.out.println("靜態程式碼塊1"); System.out.println("靜態程式碼塊2"); } }
看到編譯後的結果說明幾個問題:
- 顯示聲明構造函數後,編譯器將不會幫我們創建默認的構造函數。
- 編譯器刪除了構造程式碼塊,並將被刪除的構造程式碼塊中的程式碼,複製移動到每一個構造函數程式碼的最前面
- 編譯器會將多個靜態程式碼塊中的程式碼,整合到一個靜態程式碼塊執行。
那現在看一下創建Person對象的控制台輸出
Main.java
package cn.ttext.test.init; public class Main { public static void main(String[] args) { new Person("張三",18,"女"); System.out.println(); new Person("李四",18,"男"); } }

因為靜態程式碼塊只會隨著類的載入而運行,所以第二次創建對象時,靜態程式碼塊沒有運行。 結合上邊的知識點看,是不是更明白了呢。
轉發請註明本文鏈接。