Java非靜態程式碼塊和例項初始化過程
1 非靜態程式碼塊
非靜態程式碼塊特點
①可以為例項變數(非靜態的屬性)初始化
②每次建立物件的時候,都會執行一次,且先於構造器執行
③若有多個非靜態的程式碼塊,那麼按照定義的順序從上到下依次執行
④程式碼塊中既可以呼叫非靜態的變數和方法,也可以可以呼叫靜態的變數和方法
測試程式碼:
public class BlockTest { public static void main(String[] args) { MyClass my1 = new MyClass(); //MyClass my2 = new MyClass("java"); } } class MyClass { private String str; { System.out.println("非靜態程式碼塊1"); } public MyClass() { System.out.println("無參構造"); } public MyClass(String str) { this.str = str; System.out.println("有參構造"); } { System.out.println("非靜態程式碼塊2"); } }
執行結果:
非靜態程式碼塊1
非靜態程式碼塊2
無參構造
2 例項初始化
例項初始化過程:建立物件時,為物件進行初始化的操作
①為成員變數顯式賦值
②執行非靜態程式碼塊
③執行構造器
Java編譯器會把這三個部分的程式碼,合成一個叫做 <init>([形參列表])
例項初始化方法
即編譯後的.class位元組碼資訊中,是沒有構造器這個概念。
<init>([形參列表])
例項初始化方法的程式碼就是由三個部分組成:
①成員變數顯式賦值的程式碼
②非靜態程式碼塊中的程式碼
③構造器中的程式碼
其中①和②按定義順序依次執行,③最後執行。
而且,有幾個構造器,就會有幾個例項初始化方法。那麼當你建立物件的時候,呼叫對應的構造器時,其實執行的是對應的例項初始化方法 <init>([形參列表])
程式碼示例:
public class InitTest { public static void main(String[] args) { Demo d1 = new Demo(); //Demo d2 = new Demo("java"); } } class Demo{ { System.out.println("非靜態程式碼塊1"); } private String str = assign();//呼叫方法,為str進行顯式賦值 public Demo(){ System.out.println("無參構造"); } public Demo(String str){ this.str = str; System.out.println("有參構造"); } { System.out.println("非靜態程式碼塊2"); } public String assign(){ System.out.println("為成員變數賦值"); return "hello"; } }
3 子類例項初始化
(1)先執行父類的例項初始化方法
它由三部分組成:
-
成員變數的顯式賦值
-
非靜態程式碼塊
-
構造器
(2)再執行子類的例項初始化方法
它由三部分組成:
-
成員變數的顯式賦值
-
非靜態程式碼塊
-
構造器
super()或super(實參列表) 表面是呼叫父類的構造器,其實是呼叫父類對應的例項初始化方法
super()或super(例項列表) 表面是在子類構造器的首行,其實是在子類例項初始化方法的首行
程式碼示例:
public class InitTest2 {
public static void main(String[] args) {
Son s = new Son();
}
}
class Father {
private String strFather = assignFather();
{
System.out.println("父類的非靜態程式碼塊");
}
public Father(){
System.out.println("父類的無參構造");
}
public String assignFather(){
System.out.println("父類的assignFather()");
return "father";
}
}
class Son extends Father {
private String strSon = assignSon();
{
System.out.println("子類的非靜態程式碼塊");
}
public Son(){
//super() ==> 呼叫父類的例項初始化方法,而且它在子類例項初始化方法的首行
System.out.println("子類的無參構造");
}
public String assignSon(){
System.out.println("子類的assignSon()");
return "son";
}
}
執行結果:
父類的assignFather()
父類的非靜態程式碼塊
父類的無參構造
子類的assignSon()
子類的非靜態程式碼塊
子類的無參構造
子類為成員變數顯式賦值方法重寫父類顯式賦值方法時,呼叫的子類重寫的方法,程式碼示例:
public class InitTest3 {
public static void main(String[] args) {
Son s = new Son();
}
}
class Father {
private String strFu = assign();
{
System.out.println("父類的非靜態程式碼塊");
}
public Father(){
System.out.println("父類的無參構造");
}
public String assign(){
System.out.println("父類的assign()");
return "father";
}
}
class Son extends Father {
private String strSon = assign();
{
System.out.println("子類的非靜態程式碼塊");
}
public Son(){
//super() ==>呼叫父類的例項初始化方法,而且它在子類例項初始化方法的首行
System.out.println("子類的無參構造");
}
public String assign(){
System.out.println("子類的assign()");
return "son";
}
}
執行結果:
子類的assign()
父類的非靜態程式碼塊
父類的無參構造
子類的assign()
子類的非靜態程式碼塊
子類的無參構造