我们来看看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修饰符.静态方法与类绑定,实例方法(普通方法)与对象(类实例)绑定.构造函数从类初始化对象,因此该类必须已经完全加载.因此,将静态方法作为构造函数的一部分调用是没有问题的.
加载类和创建对象的事件序列如下:
(简化*)
在调用对象构造函数时,静态方法和变量可用.
将类及其static成员视为该类对象的蓝图.您只能在蓝图已存在时创建对象.
构造函数也称为初始化程序.如果从构造函数中抛出异常并打印堆栈跟踪,您会注意到它<init>在堆栈框架中被调用.只能在构造对象后调用实例方法.super(...)在构造函数中无法使用实例方法作为调用的参数.
如果创建同一类的多个对象,则步骤1和2仅发生一次.
(*为了清晰起见,省略了静态初始化器和实例初始化器)
是的,检查JVM规范(虽然不可否认是旧的规范):
在实例init方法中,在调用同一个类中的另一个init方法或超类中的init方法之前,可能不会引用"this"(包括返回的隐式引用).
就我所见,这确实是唯一真正的限制.