我创建了一个包含以下内容的类:
static final
变量static
带有System.out.println()
语句的初始化程序块如果我从另一个类调用static final
变量,则static
块不会执行。
据我所知,当类在内存中加载时,static
初始化程序块会执行。
在这种情况下,内存级别发生了什么?
该类是否未加载到内存中?如果没有,其他类在哪里获取final static
变量的地址?
案例1: static
阻止不执行
class Test2 {
static final int a = 20;
static {
System.out.println("one");
}
}
案例2: static
阻止 执行
class Test2 {
static final int a;
static {
a = 20;
System.out.println("one");
}
}
输出
class Test {
public static void main(String[] args) {
System.out.println(Test2.a);
}
}
案例1:
20
案例2:
one
20
那么两个层面都发生了什么?
答案 0 :(得分:11)
静态final字段是编译时常量,其值为 硬编码到目标类而不引用它 原点;
因此,您的主类不会触发类的加载 包含该字段;
因此不会执行该类中的静态初始值设定项。
从定义中查看魔术删除final
。您将看到执行静态初始化程序
答案 1 :(得分:11)
我的猜测是你的字段是原始类型或String
,并使用编译时常量表达式进行初始化。
对于使用常量表达式初始化的静态final字段(并且只有这样的字段) - 引用该字段的任何代码都将具有烘焙到其中的常量值,而不是通过将导致类初始化的静态字段。但是,“常量表达”部分很重要。我们可以通过一个小测试应用程序看到这个:
class Fields {
public static final String CONSTANT = "Constant";
public static final String NON_CONSTANT = new String("Non-constant");
static {
System.out.println("Initializing");
}
}
public class Test {
public static void main(String arg[]) {
System.out.println(Fields.CONSTANT);
System.out.println(Fields.NON_CONSTANT);
}
}
输出结果为:
Constant
Initializing
Non-constant
访问常量字段不需要初始化,但访问非常量字段会执行。使用非final字段会产生相同的效果:它基本上不再算作常量。
关于“这是一个常数”的信息被引入声明一个字段的类中。例如,使用javap -c Fields
我们会看到两个字段:
public static final java.lang.String CONSTANT;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String Constant
public static final java.lang.String NON_CONSTANT;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
请注意ConstantValue
字段元数据的CONSTANT
部分,NON_CONSTANT
字段元数据中缺少此部分。
有关构成常量表达式的更多信息,请参阅section 15.28 of the JLS。
Section 12.4.1 of the JLS指定何时初始化类:
类或接口类型T将在第一次出现以下任何一个之前立即初始化:
T是一个类,并创建了一个T实例。
T是一个类,调用T声明的静态方法。
分配由T声明的静态字段。
T声明的静态字段使用,字段不是常量变量(§4.12.4)。
T是顶级类(第7.6节),并且执行在词典中嵌套在T(第8.1.3节)内的断言语句(第14.10节)。
(强调我的。)