为什么子类的静态代码被执行?

时间:2016-02-02 10:26:57

标签: java constructor static static-methods

我编写了以下代码并为超类创建了对象。

class SuperClass{
    static int a=2;
    static int b(){
        return 2;
    }
    int c(){
        return 2;
    }

    SuperClass(){
        System.out.println("Super");
    }
    static {
        System.out.println("super");
    }
}

public class Sub extends SuperClass{
    Sub(){
    System.out.println("Sub");
    }
    static {
        System.out.println("sub");
    } 
    static int b(){
        return 3;
    }
    int c(){
        return 3;
    }
    public static void main(String ax[]){
        SuperClass f =new SuperClass();
        System.out.println(f.c());
        System.out.print(SuperClass.b());
    }   
}

当我检查输出时,它如下:

super
sub
Super
2
2

我知道只有在初始化类的对象或进行任何静态引用时才执行静态块。但在这里,我没有将这些中的任何一个发给Sub类。那为什么我看到“sub”即子类'静态块输出?

4 个答案:

答案 0 :(得分:37)

  

我知道只有在初始化类的对象或进行任何静态引用时才执行静态块。但是在这里,我没有将这些中的任何一个发给Sub类。

您的代码没有,但为了运行main,必须加载Sub。所以运行它的静态初始化器。

例如,我假设你这样运行:

java Sub

java工具必须加载Sub才能调用Sub.main。这是静态引用(访问,真的)导致静态初始化程序运行。 (如果在IDE中运行它,IDE将执行java工具部分,但结果是相同的。)

所以这就是发生的事情:

  1. java触发加载Sub

  2. JVM必须加载SuperClass才能加载Sub

  3. 因此,我们看到他们的静态初始化程序按顺序运行(SuperClass,然后是Sub):

    super
    sub
    
  4. java工具调用main

  5. main来电new SuperClass中的代码:

    Super
    
  6. main来电f.c()

    中的代码
    2
    
  7. main来电SuperClass.b中的代码:

    2
    
  8. Holger帮助points out§5.5 - Initialization中的JVM规范和相关§5.2 - Java Virtual Machine Startup

      

    类或接口的初始化包括执行其类或接口初始化方法(第2.9节)。

         

    类或接口C只能由于以下原因而初始化:

         
        
    • ...

    •   
    • 如果C是一个类,则初始化其子类之一。

    •   
    • 如果C是一个类,则将其指定为Java Virtual Machine启动时的初始类(第5.2节)。

    •   

    倒数第二个要点涵盖SuperClass,最后一个要点涵盖Sub

答案 1 :(得分:12)

由于您的main()方法是Sub的成员,因此需要加载该类才能让您的程序运行。

答案 2 :(得分:9)

在调用main时,将调用所有静态初始化程序,首先是超类,然后是子类。

这解释了你观察到的输出。

答案 3 :(得分:3)

在加载类时运行静态块。通常是因为你调用构造函数或静态成员。在这种情况下,这是因为您执行了main方法(静态成员)。

旁注:

  1. 另一个边缘案例是调用Class.forName(className)来加载一个类。
  2. 您可能还注意到基类是在子类之前加载的。