之前說過Java中類的加載順序,這次看完繼承部分,就結合繼承再來說說類的加載順序。
繼承的加載順序
由於static塊會在首次加載類的時候執行,因此下面的例子就是用static塊來測試類的加載順序。
package xing.test.thinking.chap7;
class A{
static{
System.out.println("A static");
}
}
class B extends A{
static{
System.out.println("B static");
}
}
class C extends B{
private static D d = new D();
static{
System.out.println("C static");
}
}
class D{
static{
System.out.println("D static");
}
}
public class ExtendTest {
public static void main(String[] args) {
C c = new C();
}
}
在上面的例子中,類C繼承B,B繼承A,而C有依賴於D。因此當創建C的時候,會自動加載C繼承的B和依賴的D,然后B又會加載繼承的A。只有A加載完,才能順利的加載B;BD加載完,才能加載C。這就是類的加載順序了。
A static
B static
D static
C static
所有的變量初始化完,才會執行構造方法
在類的加載過程中,只有內部的變量創建完,才會去執行這個類的構造方法。
package xing.test.thinking.chap7;
class A2{
B2 b2 = new B2();
static{
System.out.println("A static");
}
public A2() {
System.out.println("A2()");
}
}
class B2{
C2 c2 = new C2();
D2 d2 = new D2();
static{
System.out.println("B static");
}
public B2() {
System.out.println("B2()");
}
}
class C2{
static{
System.out.println("C static");
}
public C2() {
System.out.println("C2()");
}
}
class D2{
static{
System.out.println("D static");
}
public D2() {
System.out.println("D2()");
}
}
public class VarTest {
public static void main(String[] args) {
A2 a2 = new A2();
}
}
在上面的例子中,A2里面有B2變量,B2則有C2D2變量。因此類的加載還是先讀取到哪個,就執行相應的靜態塊。
當依賴的對象都定義完,才會執行構造方法:
A static
B static
C static
C2()
D static
D2()
B2()
A2()
靜態成員與普通成員類的加載區別
在類的加載過程中,靜態成員類的對象,會優先加載;而普通成員類的對象則是使用的時候才回去加載。
package xing.test.thinking.chap7;
class A3{
B3 b3 = new B3();
static C3 c4 = new C3();
static{
System.out.println("A3");
}
}
class B3{
static{
System.out.println("B3");
}
}
class C3{
static{
System.out.println("C3");
}
}
public class StaticTest {
public static void main(String[] args) {
A3 a3 = new A3();
}
}
輸出:
C3
A3
B3
總結
第一點,所有的類都會優先加載基類
第二點,靜態成員的初始化優先
第三點,成員初始化后,才會執行構造方法
第四點,靜態成員的初始化與靜態塊的執行,發生在類加載的時候。
第四點,類對象的創建以及靜態塊的訪問,都會觸發類的加載。
補充類構造方法的順序
看代碼:
package xing.test.thinking.chap8;
class A{
public A() {
System.out.println("A");
}
}
class B extends A{
public B() {
System.out.println("B");
}
}
class C extends B {
private D d1 = new D("d1");
private D d2 = new D("d2");
public C() {
System.out.println("C");
}
}
class D {
public D(String str) {
System.out.println("D "+str);
}
}
public class ExtendTest {
public static void main(String[] args) {
C c = new C();
}
}
執行結果:
A
B
D d1
D d2
C
因此可以得出結論:
- 首先會調用基類的構造方法
- 其次,調用成員的構造方法
- 最后,調用自己的構造方法