JVM如何在Java中加载父类

时间:2014-04-01 04:42:52

标签: java inheritance initialization classloader

代码:

class A {
    static {
        System.out.println("loading A static 1");
    }
    static {
        System.out.println("loading A static 2 B.c= "+B.c);        
    }
    static {
        System.out.println("loading static 3");
    }
    static int a=10; 
    A(){        
    }
}

class B extends A{
    static {
       System.out.println("loading B A.a= "+A.a);
    }
    static int c = 50;
}
public class Test {
    public static void main(String[] args) {
        new B();
    }
}

输出:

loading A static 1
loading A static 2 B.c= 0
loading static 3
loading B A.a= 10

从这个出来,我们可以说父类在子类之后加载但子类在父类之后初始化吗? 如果是这样,JVM如何加载类层次结构?

3 个答案:

答案 0 :(得分:5)

Java语言规范explains初始化类的过程。

  

类或接口类型T将在紧接之前初始化   首次出现以下任何一种情况:

     
      
  • T是一个类,并创建了一个T实例。

  •   
  • T是一个类,调用T声明的静态方法。

  •   
  • 分配由T声明的静态字段。

  •   
  • 使用T声明的静态字段,该字段不是常量变量(§4.12.4)。

  •   
  • T是顶级类(第7.6节),并且执行在词典中嵌套在T(第8.1.3节)内的断言语句(第14.10节)。

  •   

with more details

  

[...]

     

在C的初始化锁定LC上进行同步。这涉及到   等到当前线程可以获得LC。

     

[...]

     

如果C的Class对象表示正在进行初始化   对于当前线程的C,那么这必须是递归请求   初始化。释放LC并正常完成。

     

[...]

     

接下来,如果C是一个类而不是一个接口,那么它的超类SC   尚未初始化,然后递归执行这整个   SC的程序。如有必要,请先验证并准备SC。如果   由于抛出异常,SC的初始化突然完成,   然后获取LC,将C类的Class对象标记为错误,通知所有   等待线程,释放LC,并突然完成,抛出相同的   初始化SC导致的异常。

所以

new B();

要求初始化类B。由于BA的子类,因此需要初始化A。在初始化A时,这个

static {
    System.out.println("loading A static 2 B.c= "+B.c);        
}

表示B需要初始化,但B已经在初始化过程中,因此暂时忽略它,A初始化继续。 由于B的初始化未完成,因此字段c尚未初始化为50,因此会打印0

A初始化完成。 B初始化仍在继续。 B初始化完成并繁荣!你已经完成了。

答案 1 :(得分:4)

您可以通过java -verbose Test执行此操作来检查:

...
[Loaded A from file:/.../src/main/java/]
[Loaded B from file:/.../src/main/java/]
loading A static 1
loading A static 2 B.c= 0
loading static 3
loading B A.a= 10
...

所以不,首先加载父类。

答案 2 :(得分:1)

初始化类时将执行静态块。我们知道

  

在初始化类之前,必须初始化其直接超类,

因此,在您初始化B的情况下,它的超类会在此之前自动初始化。

有关详情,请查看this part of spec