[英]Constructors called due to static initialization
我正在阅读Bruce Eckel第4版的《用Java思考》。 在“初始化与清理”一章,第189页中,第二段的第一个要点提到:
即使没有显式使用static关键字,构造函数实际上也是一个静态方法。
我有以下代码:
class Bar {
Bar() {
System.out.println("Bar Creation");
}
}
class Foo {
static int x = 10;
static Bar b = new Bar();
Foo() {
System.out.println("Foo Creation");
}
}
public class Test {
public static void main(String[] args) {
System.out.println(Foo.x);
}
}
如果它是正确的,则应该调用Foo的构造函数。 我看不到以下代码会发生这种情况。
输出为:
Bar Creation
10
有人可以弄清楚这是什么意思吗?
我已尽力引用这本书。 在问题的上下文中,我认为该陈述之前或之后的部分与该陈述没有太大关系。
谢谢,
跳动
没有理由仅仅因为您提到了该类而调用Foo()
。 静态初始化器,例如static Bar b = new Bar();
当类加载时被调用; 静态方法由您的代码调用。
我猜这本书的意思是,构造函数就像静态方法一样,因为调度是静态的:也就是说,没有办法继承和覆盖构造函数,并且构造函数或静态方法的调用站点总是指在编译时确定的某些特定类。
(构造函数的这种静态性是“工厂”对象在其实例方法中构造对象的动机。)
仅仅是因为您尚未创建Foo
新实例来访问它的静态字段x
如果创建了new Foo()
,则将调用构造函数代码。 由于x是静态成员字段, 因此不需要创建holder类的实例来访问该字段。
访问x的另一种方法是new Foo().x
,但是不需要创建新的Object。
而之所以会打印“ Bar Creation”,是因为分配了Foo
声明的静态字段 。 有关初始化规范,请参见JLS 12.4.1 。
创建新对象后,将调用构造函数。 我不会把它的静态方法,因为它必须有一个实例,该实例是通过默认访问this
public class Main {
public Main() {
// static methods do not have a `this`
System.out.println("Main called" + this.getClass());
}
public static void main(String... ignore) {
new Main();
}
}
如果您反编译字节码,则可以看到static
方法
$ javap -c -p -cp . Main
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: new #3 // class java/lang/StringBuilder
10: dup
11: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
14: ldc #5 // String Main called
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: aload_0
20: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
23: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
26: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: return
public static void main(java.lang.String...);
Code:
0: new #11 // class Main
3: dup
4: invokespecial #12 // Method "<init>":()V
7: pop
8: return
}
注意: static
方法具有不同的修饰符。
除非您在Foo类上调用new(),否则不会调用构造函数。 作为new关键字在内部调用构造函数。 您只需使用类的名称访问该类的静态字段即可,而无需创建实例。
您是更新Foo,而只是将Bar作为Foo中的静态字段更新。 您无需构造类的实例就可以访问类中的静态变量。
仅在使用new
关键字时才调用构造函数。 由于您不执行new Foo()
,因此不会调用构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.