<font color="Teal"><b>前言</b></font>html
<hr> 在程序編寫之中能夠直接使用<font color=red>`{...}`</font>定義的一段語句就是代碼塊。根據代碼塊的位置以及關鍵字的不一樣能夠分爲4種:普通代碼塊、構造塊、靜態塊以及同步代碼塊(多線程相關)。下面將先介紹前3種以及Java類的初始化順序:<br> <li><a href="#1" style="text-decoration:none">普通代碼塊</a></li> <li><a href="#2" style="text-decoration:none">構造塊</a></li> <li><a href="#3" style="text-decoration:none">靜態塊</a></li> <li><a href="#4" style="text-decoration:none">Java類的初始化順序</a> <ul> <li><a href="#41" style="text-decoration:none">對於一個類(沒有繼承)的初始化狀況</a></li> <li><a href="#42" style="text-decoration:none">對於有繼承的狀況</a></li> </ul> </li>多線程
<a name="1"><font color="Teal"><b>普通代碼塊</b></font></a>函數
<hr>this
寫在方法裏面的代碼塊就是普通代碼塊spa
public static void main(String args[]){ { int num = 0; } int num=100; }
{...}
表示的是一個做用域,內部定義的變量的能夠起做用的範圍僅在{...}
這個範圍內。<br> 上面代碼中{int num=0;}
的num在離開{...}
後就被銷燬了,因而能夠在外部又能夠定義int num=100
。<br> 如果寫成如下:線程
public static void main(String args[]){ int num=100; { int num = 0; //報錯:Duplicate local variable num } }
由於外部也存在num這個變量,且有效。因此,這樣定義會出錯。<br>code
普通代碼塊的做用就是<u>爲了防止在方法中編寫代碼過多,產生變量重名,因而對一個方法中的代碼進行局部的分割</u>。可是建議一個方法中的代碼不要太長,儘可能不使用普通代碼塊<br>htm
<br> <a name="2"><font color="Teal"><b>構造塊</b></font></a> <hr> 若是將一個代碼塊放在類裏面,那麼就是一個構造塊。<br> <u>構造塊的做用是爲了給對象進行初始化</u>。咱們知道構造函數的做用也是爲了給對象進行初始化,那麼這二者有什麼區別呢?<br> ```Java public class Student { private String name; private int age;對象
//無參構造函數 public Student() { System.out.println("constructor with no args "); System.out.println("name:"+this.name + " age:"+this.age); this.name = "no name"; this.age = 18; } //有參構造函數 public Student(String name, int age){ System.out.println("constructor with args"); System.out.println("name:"+this.name + " age:"+this.age); this.name = name; this.age = age; } //構造塊 { System.out.println("constructor block "); name = "cbname"; age = 20; } public static void main(String[] args) { new Student(); System.out.println("=========="); new Student("sakura", 19); }
constructor block constructor with args name:cbname age:20 */blog
能夠看出每次建立對象時,都會調用一次構造塊,而且<b>構造塊的優先於構造函數執行</b>。有對象的建立,纔會調用構造快,類是不能調用構造塊的。<br> 構造塊與構造函數的區別在於:每一個對象被構造塊初始化的那部分變量擁有的初始值是同樣的,<b>構造塊對全部對象的效果是同樣的</b>。然而每一個對象可能會使用不一樣構造函數,<b>不一樣的構造函數初始化對象的方式是不一樣的</b>。 <br> <a name="3"><font color="Teal"><b>靜態塊</b></font></a> <hr> 使用static修飾的代碼塊就叫作靜態代碼塊或者直接叫靜態塊。<br> 前面在介紹<a style="text-decoration:none" target="_blank" href="https://www.cnblogs.com/myworld7/p/10052245.html#23" > <b>static關鍵字</b></a>(能夠回顧查看)時,介紹了一部分static修飾代碼塊的知識。 * 靜態塊在類加載時執行,且只會<b>執行一次</b>,<b>執行順序優先主函數、構造函數和構造塊</b>。 * 靜態代碼塊主要用於<b>初始化類中的static屬性(類屬性)</b>,而構造塊是初始化對象中的屬性 * 一個類中能夠有多個靜態代碼塊, 執行順序依照靜態代碼塊的聲明順序。靜態代碼塊<b>能夠在類的任意位置定義,在方法中不能夠聲明靜態塊</b>。 <br> <a name="4"><font color="Teal"><b>Java類的初始化順序</b></font></a> <hr> <br> <a name="41"><font color="#a5615f"><b>對於一個類(沒有繼承)的初始化狀況</b></font></a> <hr> ```Java public class Student { private String name="no name"; private int age=18; private static int id=1; //無參構造函數 public Student() { System.out.println("======"); System.out.println("無參構造函數"); System.out.println("姓名:"+name+" 年齡:"+age); } //有參構造函數 public Student(String name, int age){ System.out.println("======"); System.out.println("有參構造函數"); System.out.println("姓名:"+this.name+" 年齡:"+this.age); this.name = name; this.age = age; System.out.println("姓名:"+this.name+" 年齡:"+this.age); } //構造塊 { System.out.println("======"); System.out.println("構造塊"); System.out.println("姓名:"+this.name+" 年齡:"+this.age); this.name = "cbname"; this.age = 18; } //靜態代碼塊 static { System.out.println("======"); System.out.println("靜態塊"); System.out.println("靜態變量id="+id); } public static void main(String[] args) { System.out.println("======"); System.out.println("主方法"); new Student(); new Student("小王",20); } } /* output: ====== 靜態塊 靜態變量id=1 ====== 主方法 ====== 構造塊 姓名:no name 年齡:18 ====== 無參構造函數 姓名:cbname 年齡:18 ====== 構造塊 姓名:no name 年齡:18 ====== 有參構造函數 姓名:cbname 年齡:18 姓名:小王 年齡:20 */
對於一個類而言:<br>
靜態代碼塊、構造代碼塊、構造函數和主函數的執行順序爲:
<font color="red">靜態代碼塊>主函數>構造代碼塊>構造函數</font>
在加上靜態屬性、普通屬性,他們的初始化執行順序就爲:
<font color="red">靜態變量、靜態代碼塊 > 主函數 > 指定初始值的屬性 > 構造代碼塊 > 構造函數</font>
<br> <a name="42"><font color="#a5615f"><b>對於有繼承的狀況</b></font></a> <hr> ```Java class Person{ private String name="Person沒有名字"; private int age=10; private static int id=1; //無參構造函數 public Person() { System.out.println("======"); System.out.println("Person無參構造函數"); System.out.println("Person 姓名:"+this.name+" 年齡:"+this.age); }
//構造塊 { System.out.println("======"); System.out.println("Person 構造塊"); System.out.println("Person 姓名:"+this.name+" 年齡:"+this.age); this.name = "pcbname"; this.age =11 ; } //靜態代碼塊 static { System.out.println("======"); System.out.println("Person 靜態塊"); System.out.println("Person 靜態變量id="+id); }
} public class Student extends Person{ private String name="Student沒有名字"; private int age=18; private static int id=2; //無參構造函數 public Student() { //自動調用父類的無參構造函數 super(); System.out.println("======"); System.out.println("Student無參構造函數"); System.out.println("Student 姓名:"+this.name+" 年齡:"+this.age); }
//有參構造函數 public Student(String name, int age) { //自動調用父類的無參構造函數 super(); System.out.println("======"); System.out.println("Student有參構造函數"); System.out.println("Student 姓名:"+this.name+" 年齡:"+this.age); this.name = name; this.age = age; } //構造塊 { System.out.println("======"); System.out.println("Student 構造塊"); System.out.println("Student 姓名:"+this.name+" 年齡:"+this.age); this.name = "scbname"; this.age = 19; } //靜態代碼塊 static { System.out.println("======"); System.out.println("Student 靜態塊"); System.out.println("Student 靜態變量id="+id); } public static void main(String[] args) { System.out.println("======"); System.out.println("主方法"); System.out.println("\n--------第一次建立Studet對象--------"); new Student(); System.out.println("\n--------第二次建立Studet對象--------"); new Student("小夏",20); }
主方法
Student無參構造函數 Student 姓名:scbname 年齡:19
Student有參構造函數 Student 姓名:scbname 年齡:19 */
觀察代碼結果,分析,對於有繼承關係的類,初始化順序按以下進行: > 1. 執行父類的靜態代碼塊,並初始化父類靜態成員變量 2. 執行子類的靜態代碼塊,並初始化子類靜態成員變量 3. 執行父類的構造代碼塊,執行父類的構造函數,若普通成員變量指定了初始值則先執行初始值的賦值,而後返回執行構造函數 4.執行子類的構造代碼塊,執行子類的構造函數,若普通成員變量指定了初始值則先執行初始值的賦值,而後返回執行構造函數 <br> <font color="Teal"><b>小結</b></font> <hr> 本文介紹的三種代碼塊,普通塊和構造塊都不建議使用,靜態塊可使用用於初始化靜態變量。<br> 理清Java程序初始化的執行順序能夠很清楚地掌握程序的執行過程。<br> 對一個類而言,`靜態變量和靜態代碼塊> 主函數 > 指定初始值的屬性 > 構造代碼塊 > 構造函數`<br> 對於有繼承的來講,`父類靜態塊和靜態變量 > 子類靜態塊和靜態變量 > 父類指定初始值的屬性 > 父類構造塊 > 父類構造函數 > 子類指定初始值的屬性 > 子類構造塊 > 子類構造函數`<br> 參考博客: <https://www.cnblogs.com/Qian123/p/5713440.html>