2016-02-02 41 views
24

我写了下面的代码并为超类创建了对象。为什么子类的静态代码得到执行?

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”即子类的静态块输出?

+11

执行'main'方法(嵌套在'Sub'类中)是一个静态引用。 :) –

+0

@KonstantinYovkov我想过,但即使如此,“子”应该是第一个正确的。现在,这个疑问从Bathsheba的答案中清除了,因为静态块按照超类和子类的顺序执行。谢谢。 – AV94

+3

@anil首先,'Sub'类仍然依赖于'Super'类,因此它首先被执行。 – njzk2

回答

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 
    

作为Holger有益points out,这是通过JVM规范中§5.5 - Initialization覆盖,并且相关§5.2 - Java Virtual Machine Startup

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

类或接口C可以被初始化仅作为结果:

  • ...

  • 如果C是一类,它的子类中的一个的初始化。

  • 如果C是一个类,它的名称作为Java虚拟机启动(§5.2)中的初始类。

这第二个到最后的子弹对焦点覆盖SuperClass,最后的子弹点覆盖Sub

12

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

9

在调用main时,首先调用所有静态初始化器,首先在超类中调用,然后调用子类。

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

3

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

侧笔记:

  1. 另一边缘情况下调用的Class.forName(类名)加载的类。
  2. 您可能还注意到,基类是在子类之前加载的。