我的java类
private static final String constantString = "Constant";
private static final Integer constantInteger = 5;
public static void main(String[] args) {
String s2 = constantString + "append"; // LINENUMBER 9
Integer i2 = constantInteger + 7; // LINENUMBER 10
}
字节代码
LINENUMBER 9 L0
LDC "Constantappend"
ASTORE 1
L1
LINENUMBER 10 L1
GETSTATIC TestClass.constantInteger : Ljava/lang/Integer;
INVOKEVIRTUAL java/lang/Integer.intValue()I
BIPUSH 7
IADD
问题1:为什么编译器没有用5替换最终的Integer(constantInteger)值,但是对于String,它确实没有!
如果删除整数变量的最终关键字
java代码:
private static Integer constantInteger = 5;
字节代码:
LINENUMBER 10 L1
GETSTATIC TestClass.constantInteger : Ljava/lang/Integer;
INVOKEVIRTUAL java/lang/Integer.intValue()I
BIPUSH 7
两种不同情况下的字节代码相同(静态最终整数,静态整数)
问题2:那么使Integer最终有什么用?
答案 0 :(得分:6)
推测:原因是字符串实习。编译器实例化字符串并具有连接字符串连接的优化。但它没有实习数字,显然缺乏优化。
我想不出有什么理由不能优化整数情况,除了它还没有在编译器中实现。正如其他答案中所提到的,Integer +涉及装箱/拆箱操作,与字符串+及其隐式StringBuilder优化和实际逻辑完全不同。因此,如果查看,String +优化可能从编译器实现点“免费”出现。
答案 1 :(得分:5)
编译器不会注意到具有非null值的最终Integer必然是非null。所以它继续并将其拆箱。 JIT编译器完全有可能在加工机器代码的过程中改进这一点;对于应用程序的性能来说,这似乎是不太可能的。
'最终'是关于语义,而不是表现。语言保证了语义;性能完全是实现者的心血来潮。所以,回答问题#2'显式:最后一点是具有防止修改的语义。还要注意嵌入式匿名类的规则,它们只能使用最终的局部变量。
答案 2 :(得分:3)
答案简短:尝试static final int constantInteger = 5
编译器只能替换常量表达式。 Java具有所谓的原始值,即以小写字符(long,int,char,...)开头的类型。这些值不是对象,因此它们不能具有状态并且可以直接替换。
作为优化字符串对象也可以被编译器视为常量。在运行时,String只是一个容纳字符数组的容器,但在编译时,编译器假装String只是字符数据。但是,String
是唯一一个针对此例外的类。
出于类似的原因,您可以使用String
和Class
,但注释中的值没有其他对象类型。
答案 3 :(得分:1)
来自Java Language Specification, v3:
由常量表达式计算的字符串(第15.28节)计算在 编译时间,然后将其视为文字。
您的字符串表达式由两个文字组成,在编译时计算为单个文字。整数没有这样的待遇。