创建对类对象的引用是否会导致加载类? 加载类时会初始化静态变量,所以考虑到以下代码,答案是否定的,我是对的吗?
class A{
static int f(){
System.out.println("initializing!");
return 0;
}
static final int i = f();
}
public class Main {
public static void main(String[] args) {
A a;
}
}
代码没有输出。
答案 0 :(得分:5)
是。调用类方法或实例化实例时,将调用静态初始值设定项。
从您的示例中,您可以执行以下操作之一:
public static void main(String[] args) {
A a = new A();
}
public static void main(String[] args) {
int f = A.f();
}
答案 1 :(得分:2)
将类的加载和初始化视为同一个事情是一个常见的错误。
加载是指查找具有特定名称的类或接口类型的二进制形式的过程,可能是通过动态计算,但更常见的是通过检索先前从中计算的二进制表示Java编译器的源代码,并从该二进制形式构造一个
Class
对象来表示类或接口。
链接是获取类或接口类型的二进制形式并将其组合到Java虚拟机的运行时状态的过程,以便可以执行它。在链接之前始终加载类或接口类型。
链接涉及三种不同的活动:符号引用的验证,准备和解决。
类的初始化包括执行其
static
初始值设定项和类中声明的静态字段(类变量)的初始值设定项。
接口的 Initialization 包括执行接口中声明的字段(常量)的初始值设定项。
对于大多数情况,加载和链接的确切时间无关紧要,因此规范为JVM实现提供了一些关于确切时间的自由度是没有问题的。只有在错误的情况下,例如当一个类不存在或存在不兼容性(链接或验证错误)时,可能会出现JVM特定的差异,关于引发关联的Error
的确切时间。
所以你的问题是针对的,不是加载,而是初始化,因为你正在研究执行static
所产生的副作用阶级初始化。
初始化时间为precisely defined:
§12.4.1。初始化发生时
类或接口类型T将在第一次出现以下任何一个之前立即初始化:
T
是一个类,并创建了T
的实例。- 调用
static
声明的T
方法。- 分配了
static
声明的T
字段。- 使用
static
声明的T
字段,该字段不是常量变量(§4.12.4)。T
是一个顶级课程(§7.6)和一个assert
语句(§14.10)词汇量嵌套在T
(§8.1.3)中被执行。初始化类时,会初始化其超类(如果它们之前未初始化),以及声明任何默认方法(§8.1.5)的任何超接口(§9.4.3)(如果它们以前没有初始化)。接口的初始化本身不会导致其任何超接口的初始化。
因此,从规范中,您可以得出结论,仅仅存在局部变量永远不会触发初始化。将非null
值分配给引用类型的变量时,必须存在已触发其初始化的该类型的先前实例化。但是,未使用的局部变量没有影响。
当谈到加载而不是初始化时,可能存在细微差别,如this scenario所示。