在super()的参数列表中调用静态方法在Java中是有效的.为什么?

Lio*_*ion 13 java static

我们来看看Java中的以下代码片段.

package trickyjava;

class A
{
    public A(String s)
    {
        System.out.println(s);
    }
}

final class B extends A
{
    public B()
    {
        super(method());      // Calling the following method first.      
    }

    private static String method()
    {
        return "method invoked";
    }
}

final public class Main
{
    public static void main(String[] args)
    {
        B b = new B();
    }
}
Run Code Online (Sandbox Code Playgroud)

按照惯例,Java中的super()构造函数必须是相关构造函数体中的第一个语句.在上面的代码中,我们在super()构造函数参数列表中调用静态方法本身是super(method()); .


这意味着在构造函数B()中对super的调用中,在调用super之前调用了一个方法!这应该被编译器禁止,但它很好用.这有点等同于以下陈述.

String s = method();
super(s);
Run Code Online (Sandbox Code Playgroud)

但是,它是非法的,导致编译时错误,指示"调用super必须是构造函数中的第一个语句".为什么?为什么它等价超级(method()); 是有效的,编译器不再抱怨?

Bar*_*end 10

这里的关键是static修饰符.静态方法与绑定,实例方法(普通方法)与对象(类实例)绑定.构造函数从类初始化对象,因此该类必须已经完全加载.因此,将静态方法作为构造函数的一部分调用是没有问题的.

加载类和创建对象的事件序列如下:

  1. 载入类
  2. 初始化静态变量
  3. 创建对象
  4. 初始化对象< - 与构造函数
  5. 对象现在可以使用了

(简化*)

在调用对象构造函数时,静态方法和变量可用.

将类及其static成员视为该类对象的蓝图.您只能在蓝图已存在时创建对象.

构造函数也称为初始化程序.如果从构造函数中抛出异常并打印堆栈跟踪,您会注意到它<init>在堆栈框架中被调用.只能在构造对象后调用实例方法.super(...)在构造函数中无法使用实例方法作为调用的参数.

如果创建同一类的多个对象,则步骤1和2仅发生一次.

(*为了清晰起见,省略了静态初始化器和实例初始化器)


Hot*_*cks 5

是的,检查JVM规范(虽然不可否认是旧的规范):

在实例init方法中,在调用同一个类中的另一个init方法或超类中的init方法之前,可能不会引用"this"(包括返回的隐式引用).

就我所见,这确实是唯一真正的限制.