之前一直搞錯,這裏總結一下java類加載順序
一個類中主要有如下成員:
普通對象變量,靜態對象變量,靜態方法,普通代碼塊,靜態代碼塊,普通方法。
總體規則:
靜態在非靜態之前初始化(無論父類還是子類)
先初始化父類,再初始化子類,子類只有靜態初始在父類其他非靜態初始之前,其他等父類初始化完畢,再初始化自己
靜態對象變量,靜態代碼塊初始化順序看具體代碼順序
普通對象變量,普通代碼塊初始化順序看具體代碼順序
構造函數在最後,無論書寫順序
靜態方法,普通方法調用時才初始化
銷燬時,先銷燬子類,再銷燬父類
靜態變量,靜態代碼塊只初始化一次
例子:
提供測試的Name.java
public class Name {
public Name(String value) {
System.out.println(value);
}
}
父類Animal.java
public class Animal {
static {
System.out.println("father: static code block");
}
public Animal() {
System.out.println("father: constructor");
}
Name n1 = new Name("father: variable");
{
System.out.println("father: code block");
}
static Name n2 = new Name("father: static variable");
}
子類Bird.java
public class Animal {
static {
System.out.println("father: static code block");
}
public Animal() {
System.out.println("father: constructor");
}
Name n1 = new Name("father: variable");
{
System.out.println("father: code block");
}
static Name n2 = new Name("father: static variable");
}
運行結果:
father: static code block
father: static variable
child: static variable
child: static code block
father: variable
father: code block
father: constructor
child: code block
child: variable
child: constructor
子類初始化時候,默認尋找父類不帶參數的構造函數,如果找不到,那就說明父類提供了一個帶參的構造函數,那麼子類必須用super關鍵字顯示調用,而且必須放在自己構造函數第一行。而且此時只用帶參的構造函數初始化。
例子:修改Animal.java
public class Animal {
static {
System.out.println("father: static code block");
}
public Animal() {
System.out.println("father: constructor");
}
public Animal(int i) {
System.out.println("father: constructor parameter");
}
Name n1 = new Name("father: variable");
{
System.out.println("father: code block");
}
static Name n2 = new Name("father: static variable");
}
修改Bird.java
public class Bird extends Animal {
static Name n4 = new Name("child: static variable");
{
System.out.println("child: code block");
}
static {
System.out.println("child: static code block");
}
Bird() {
super(1);
System.out.println("child: constructor");
}
Name n3 = new Name("child: variable");
public static void main(String[] args) {
new Bird();
}
}
執行結果:
father: static code block
father: static variable
child: static variable
child: static code block
father: variable
father: code block
father: constructor parameter
child: code block
child: variable
child: constructor
注意:
如果我將代碼main函數修改爲如下這個樣子,那麼輸出結果是什麼呢?
public static void main(String[] args) {
System.out.println("before main");
new Bird();
}
執行結果:
father: static code block
father: static variable
child: static variable
child: static code block
before main
father: variable
father: code block
father: constructor parameter
child: code block
child: variable
child: constructor
爲什麼呢?
執行main函數之前,java先加載這個類,static是類變量,因此需要先執行。如果我們在另外一個函數裏面寫上述main函數,那麼before main就打印了,請看:
Client.java
public class Client {
public static void main(String[] args) {
System.out.println("before main");
new Bird();
}
}
執行結果:
before main
father: static code block
father: static variable
child: static variable
child: static code block
father: variable
father: code block
father: constructor parameter
child: code block
child: variable
child: constructor
再測試一下,靜態變量只初始化一次
Client.java
public class Client {
public static void main(String[] args) {
System.out.println("before main");
new Bird();
System.out.println("second initial");
new Bird();
}
}
執行結果:
before main
father: static code block
father: static variable
child: static variable
child: static code block
father: variable
father: code block
father: constructor parameter
child: code block
child: variable
child: constructor
second initial
father: variable
father: code block
father: constructor parameter
child: code block
child: variable
child: constructor