4

我的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 却做到了!

如果删除整数变量的最终关键字

爪哇代码:

private static Integer constantInteger = 5;

字节码:

LINENUMBER 10 L1
GETSTATIC TestClass.constantInteger : Ljava/lang/Integer;
INVOKEVIRTUAL java/lang/Integer.intValue()I
BIPUSH 7

字节码在两种不同的情况下是相同的(静态最终整数,静态整数)

问题2:那么将Integer设为final有什么用?

4

4 回答 4

6

推测:原因是字符串实习。编译器对字符串进行实习,并对实习字符串的连接进行了优化。但它不实习数字,显然缺乏优化。

我想不出它不能优化 Integer 情况的任何原因,除了它只是没有在编译器中实现。如其他答案所述,Integer + 涉及装箱/拆箱操作,与 string + 及其隐式 StringBuilder 优化和实习逻辑完全不同。因此,如果从编译器实现的角度来看,String + 优化可能是“免费”的。

于 2012-11-17T14:23:13.593 回答
5

编译器不会注意到具有非空值的最终 Integer 必然是非空的。所以它继续并拆箱。JIT 编译器完全有可能在生成机器代码的过程中改进这一点;无论哪种方式,这似乎都不太可能对您的应用程序的性能造成真正的问题。

'final' 是关于语义,而不是性能。语言保证语义;性能完全取决于实施者的心血来潮。因此,要明确回答“问题 #2”:final 的重点是具有防止修改的语义。还要注意嵌入式匿名类的规则,它们只能使用最终局部变量。

于 2012-11-17T14:20:25.750 回答
3

简短的回答:试试static final int constantInteger = 5

编译器只能替换常量表达式。Java 有所谓的原始值,即以小写字符开头的类型(long、int、char、...)。这些值不是对象,因此它们不能有状态并且可以直接替换。

作为优化String对象也可以被编译器视为常量。在运行时,String 只是一个包含字符数组的容器,但在编译时,编译器会假装 String 只是字符数据。但是,String是唯一发生此异常的类。

出于类似的原因,您可以使用Stringand Class,但不能使用其他对象类型作为注释中的值。

于 2012-11-17T14:17:56.860 回答
1

来自Java 语言规范 v3

由常量表达式(第 15.28 节)计算的字符串在编译时计算,然后将其视为文字。

您的字符串表达式由两个文字组成,在编译时被计算为单个文字。整数没有这样的处理。

于 2012-11-17T14:32:21.863 回答