Java 所有编译时常量都是内联的吗?

Java 所有编译时常量都是内联的吗?,java,inlining,compile-time-constant,Java,Inlining,Compile Time Constant,假设我有一门课是这样的: class ApplicationDefs{ public static final String configOption1 = "some option"; public static final String configOption2 = "some other option"; public static final String configOption3 = "yet another option"; } 我的应用程序中的许多其他类都在使用这些选项。现在

假设我有一门课是这样的:

class ApplicationDefs{
public static final String configOption1 = "some option";
public static final String configOption2 = "some other option";
public static final String configOption3 = "yet another option";
}
我的应用程序中的许多其他类都在使用这些选项。现在,我想单独更改其中一个选项,并只部署已编译的类。 但是如果这些字段在消费者类别中排列,这就不可能了,对吗


是否有任何选项可以禁用编译时常量的内嵌功能?

没有,恐怕这是JLS的一部分。这在Java拼图游戏中简单地提到过,但我手头上没有我的副本

我猜您可能会考虑在属性文件中定义这些常量,并有定期加载它们的类。


参考:

实际上,如果删除
final
关键字
常量将不再是编译时常量,那么您的配置将按照您的意愿工作


但是,强烈建议,如果这确实是您正在尝试执行的某种配置,则应采用比某些类文件中的常量更易于管理的方式。

否。您可以使用静态方法调用来替换它们,例如:

class ApplicationDefs {

    public static String configOption1() { return "some option"; }

}

当然,它并不漂亮,但可以满足您的要求。:)

这里没有说明这些值应该内联。您只是在声明一些
公共
静态
成员。这些其他类正在使用这些成员的值。不需要内联。即使是
final
关键字

但是由于性能原因,一些JVM可能会在其他类中内联这些值。这是一个优化。任何优化都不应改变程序的行为。因此,如果更改这些成员的定义,JVM应该取消内联以前的值

这就是为什么没有办法关闭内联。JVM不内联并且没有问题,或者如果它是内联的,JVM保证取消内联


我不确定静态导入这个类时会发生什么。我认为(不确定)内联已经执行,可能会导致您提到的问题。如果是这样的话,您基本上可以删除静态导入,这样就可以了。

您可以通过设置常量非编译时常量来禁止内联

例如,
null
不是编译时常量。任何涉及非编译时常量的表达式都不是编译时常量,尽管javac可以在编译单元内进行常量折叠

public static final String configOption1 = null!=null?"": "some option";
您可以使用String.intern()来获得所需的效果,但应该对代码进行注释,因为没有多少人知道这一点。i、 e

public static final String configOption1 = "some option".intern();
这将阻止编译时内联。因为它引用的是编译器将放入perm中的完全相同的字符串,所以您没有创建任何额外的内容

作为一种选择,你可以一直这样做

public static final String configOption1 = "some option".toString();
不过,这不会使用已编译的intern字符串,它将在旧版本上创建一个新的。这不是什么大问题,可能更容易阅读。无论哪种方式,由于这有点奇怪,您应该对代码进行注释,以告知维护代码的人员您正在做什么

编辑: 找到了另一个SO链接,该链接提供了JLS的参考,以获取有关此链接的更多信息。

我认为情况并非如此:JLS指定编译时常量始终是内联的。此外,在字符串编译时常量的情况下,它们是内部的,所有使用都引用同一个实例。如果使用JAD反编译代码,您会发现所有编译时常量都已内联。我会投票支持属性文件或描述的静态方法。此解决方案使行为与我的答案中建议的行为相同。我不认为在方法中包装常量有什么意义。@Yuval-除了在您建议的答案中,变量可以由外部类更改。实际上,如果删除final关键字,常量将不再是常量,它们将是变量。代码
aString.toString()
返回
aString
本身,而不是新的,因此,就本问题而言,它与
intern()
一样有效。很少使用的构造函数
newstring(aString)
将创建一个新的字符串副本。创建
intern()
字符串文本是无用的。他们已经被“拘留”。请参阅。@ceving-在这种情况下,它不是无用的,因为它可以防止
configOption1
等被列在其他类中。否则,如果其他一些类引用了
configOption1
,然后您更改了常量,并且没有重新编译其他类,那么行为将不是您所期望的(或可能希望的)。这就是OP问题的全部要点。