Java JLS是否需要最终字符串常量的内联?
我在操作某些字节码时遇到了一个问题,java编译器(java 8)没有内联某个Java JLS是否需要最终字符串常量的内联?,java,java-8,language-lawyer,javac,jls,Java,Java 8,Language Lawyer,Javac,Jls,我在操作某些字节码时遇到了一个问题,java编译器(java 8)没有内联某个final字符串常量,请参见下面的示例: public class MyTest { private static final String ENABLED = "Y"; private static final String DISABLED = "N"; private static boolean isEnabled(String key) { return key.equals("A
final
字符串
常量,请参见下面的示例:
public class MyTest
{
private static final String ENABLED = "Y";
private static final String DISABLED = "N";
private static boolean isEnabled(String key) {
return key.equals("A");
}
private static String getString(String key, String value) {
return key + value;
}
public static void main(String[] args) throws Exception {
String flag = getString("F", isEnabled("A") ? ENABLED : DISABLED);
System.out.println(flag);
String flag2 = getString("F", isEnabled("A") ? ENABLED : DISABLED);
System.out.println(flag2);
}
}
使用javac生成的字节码(1.8.0_101)
您可以看到,在第二次访问字段ENABLED
和DISABLED
时,编译器没有内联它们的值(使用ldc
),而是使用getstatic
直接访问字段。用其他编译器(Java7、Eclipse)测试它不会触发相同的行为,并且常量总是内联的
这可能被认为是编译器错误,还是根据JLS允许不始终内联字符串常量?是的,“内联”行为由规范强制执行:
V
如果此类字段是静态的,则二进制文件中的代码中不应存在对该字段的引用,包括声明该字段的类或接口。此类字段必须始终显示为已初始化(§12.4.2);绝不能遵守字段的默认初始值(如果与V
)的规定
如果此类字段是非静态的,则二进制文件中的代码中不应存在对该字段的引用,包含该字段的类除外。(它将是一个类而不是一个接口,因为接口只有静态
字段。)该类应该有代码在实例创建期间将字段的值设置为V
(§12.5)静态的
,那么二进制文件中的代码中不应该存在对该字段的引用,包括声明该字段的类或接口”
换句话说,如果您遇到一个编译器不遵守此规则,您会发现一个编译器错误
作为附录,查找这些信息的起点是: 常量变量是原语类型或类型为
String
的final
变量,用常量表达式()初始化。变量是否为常量变量可能涉及类初始化()、二进制兼容性(、)和确定赋值()
定义“内联”。JLS需要共享。这就是您所说的吗?内联意味着用直接将常量值推送到堆栈上的指令替换getstatic指令,例如字符串情况下的ldc,或iconst_X/bipush/sipush/。。。对于整数原语,…@piet.t:我删除了字节码标记,因为语言规范实际上不处理字节码。然而,行为的定义没有歧义,这就允许回答这个问题。这确实是一个bug,它已经被JDK 9中集成的修复程序修复,并被后传到JDK 1.8.0_102,即1.8.0_101加上一个补丁集。请注意,JDK-8066871有不同的症状,但相同的修复程序纠正了该错误以及此处描述的错误。我刚刚提交了一份错误报告(JI-9043578),因为我在错误数据库中没有找到相关条目。我想它可以关闭了。非常感谢,这正是我想要的,因此这证实了观察到的行为确实是一个编译器错误。我检查了所有这些引用,除了二进制兼容性:)
public static void main(java.lang.String[]) throws java.lang.Exception;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: ldc #8 // String F
2: ldc #2 // String A
4: invokestatic #9 // Method isEnabled:(Ljava/lang/String;)Z
7: ifeq 16
10: getstatic #10 // Field ENABLED:Ljava/lang/String;
13: goto 19
16: getstatic #11 // Field DISABLED:Ljava/lang/String;
19: invokestatic #12 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
22: astore_1
23: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_1
27: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: ldc #8 // String F
32: ldc #2 // String A
34: invokestatic #9 // Method isEnabled:(Ljava/lang/String;)Z
37: ifeq 46
40: getstatic #10 // Field ENABLED:Ljava/lang/String;
43: goto 49
46: getstatic #11 // Field DISABLED:Ljava/lang/String;
49: invokestatic #12 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
52: astore_2
53: getstatic #13 // Field java/lang/System.out:Ljava/io/PrintStream;
56: aload_2
57: invokevirtual #14 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
60: return