为什么null不是编译时常量?

因此,如果我有一个static final Object CONSTANT = null ,由于某种原因,如果我在另一段代码中引用它,如doSomething(CONSTANT) ,它将不会在编译期间嵌入到代码中。 所以编译后不是doSomething(null) ,而是doSomething(CONSTANT)

您的CONSTANT不是编译时常量,因为JLS 说它不是。 可以在常量表达式中使用的唯一类型是基本类型和String

它的意义在于Object实例(通常)具有语义上重要的对象标识,可以将其与其他Object实例区分开来。 此对象标识不能在类文件中编码…或者至少,它不能使用当前的类文件格式进行编码。 (如果可以,会有各种其他问题……)

null (理论上)可以作为特例处理,除了没有太多意义。 具体而言,您不能在语言学角度要求(或有利)“编译时间常数”的任何上下文中使用null 。 例如:

  • 您不能将null作为case表达式。
  • 由于引用类型的==不是常量表达式,因此不能将它用于Java“条件编译”惯用法,该惯用法涉及使用常量表达式作为条件的if 。 (除了null == null不是一个有用的条件……)

就内联而言,虽然“常量”不能在字节码中内联(因为关于“常量表达式”是什么的JLS规则),JIT编译器的优化器将被允许执行此操作,并且实际上可以执行此操作……如果有切实的性能优势。

参考:

  • JLS 15.28 – 常量表达式

在您的情况下, CONSTANT不是编译时间常量。

编译时常量是一个常量,它的值在编译时是已知的并且不会进一步改变,然后编译器将代码中的常量名称替换为其值。

通常,使用final声明的基本类型或字符串文字将被编译器视为编译时常量。 例:

 final int a=10; final String constant =”this is compile time const”; 

这两者都是编译时常量,我们可以在switch语句的case标签中使用Compile-time常量表达式

非编译时常量的示例

 final String xyz = new String(”this is not a compile time const"); 

这里xyz字符串对象不是编译时常量。因为这个’xyz’字符串对象将在运行时创建,这里编译器只知道引用而不是字符串对象。

这同样适用于您的静态最终Object CONSTANT = null

加入JLS

null文字的类型是null类型;其值是空引用。