Jvm 确定字符串是否为编译时常量
给定对任何Jvm 确定字符串是否为编译时常量,jvm,compile-time-constant,string-interning,Jvm,Compile Time Constant,String Interning,给定对任何字符串的引用,是否可以通过编程确定这是否是对编译时常量的引用? 或者如果不是,那么它是否存储在实习生池中而不执行s.intern()==s isConst("foo") -> true isConst("foo" + "bar") -> true // 2 literals, 1 compile time string isConst(SomeClass.SOME_CONST_STRING) -&g
字符串的引用,是否可以通过编程确定这是否是对编译时常量的引用?
或者如果不是,那么它是否存储在实习生池中而不执行s.intern()==s
isConst("foo") -> true
isConst("foo" + "bar") -> true // 2 literals, 1 compile time string
isConst(SomeClass.SOME_CONST_STRING) -> true
isConst(readFromFile()) -> false
isConst(readFromFile().intern()) -> false // true would be acceptable too
(下面评论的上下文:最初提出的关于文字的问题)为了澄清最初的问题,每个字符串文字都是编译时常量,但并非每个编译时常量都必须来自字符串文字
在运行时,为编译时常量构造的字符串
对象与通过其他方式构造的对象之间没有区别。为编译时常量构造的字符串会自动添加到池中,但其他字符串可以通过intern()
手动添加到同一池中。由于字符串是惰性构造和添加的,因此甚至可以手动构造和添加字符串,以便稍后将具有相同值的编译时常量解析为该字符串。利用这种可能性,检测编译时常量的字符串
实例何时实际解析
可以从该答案中派生出一种方法来简单地检测字符串是否在池中:
public static boolean isInPool(String s) {
return s == new String(s.toCharArray()).intern();
}
newstring(s.toCharArray())
构造一个内容相同的字符串,该字符串不在池中,如果s
引用池中的实例,则对其调用intern()
必须解析为与s
相同的引用。否则,intern()
可能解析到另一个现有对象,或者添加我们的字符串或新构造的字符串,并返回对它的引用,具体取决于实现,但在任何一种情况下,返回的引用都不同于s
请注意,此方法的副作用是,如果以前不存在字符串,则将其添加到池中,该字符串将至少保留到下一个垃圾收集周期,可能一直保留到下一个完整gc,具体取决于实现
测试方法对于调试或满足好奇心来说可能很好,但在生产代码中使用它是没有意义的。应用程序代码不应该依赖于该属性,而注释中提出的用例(在性能关键型代码中强制使用池字符串)不是一个好主意
除了测试本身很昂贵并且与性能改进的目的背道而驰之外,池化字符串优于非池化字符串的基本假设是有缺陷的。不在池中并不意味着应用程序将在每次调用性能关键代码时执行昂贵的重构。它可以简单地将引用保存在变量中或使用HashMap
,这两种方法都比调用intern()
更有效。事实上,在某些情况下,即使是临时字符串也可能是最有效的解决方案。为了澄清最初的问题,每个字符串文字都是编译时常量,但并非每个编译时常量都必须来自字符串文字
在运行时,为编译时常量构造的字符串
对象与通过其他方式构造的对象之间没有区别。为编译时常量构造的字符串会自动添加到池中,但其他字符串可以通过intern()
手动添加到同一池中。由于字符串是惰性构造和添加的,因此甚至可以手动构造和添加字符串,以便稍后将具有相同值的编译时常量解析为该字符串。利用这种可能性,检测编译时常量的字符串
实例何时实际解析
可以从该答案中派生出一种方法来简单地检测字符串是否在池中:
public static boolean isInPool(String s) {
return s == new String(s.toCharArray()).intern();
}
newstring(s.toCharArray())
构造一个内容相同的字符串,该字符串不在池中,如果s
引用池中的实例,则对其调用intern()
必须解析为与s
相同的引用。否则,intern()
可能解析到另一个现有对象,或者添加我们的字符串或新构造的字符串,并返回对它的引用,具体取决于实现,但在任何一种情况下,返回的引用都不同于s
请注意,此方法的副作用是,如果以前不存在字符串,则将其添加到池中,该字符串将至少保留到下一个垃圾收集周期,可能一直保留到下一个完整gc,具体取决于实现
测试方法对于调试或满足好奇心来说可能很好,但在生产代码中使用它是没有意义的。应用程序代码不应该依赖于该属性,而注释中提出的用例(在性能关键型代码中强制使用池字符串)不是一个好主意
除了测试本身很昂贵并且与性能改进的目的背道而驰之外,池化字符串优于非池化字符串的基本假设是有缺陷的。不在池中并不意味着应用程序将在每次调用性能关键代码时执行昂贵的重构。它可以简单地将引用保存在变量中或使用HashMap
,这两种方法都比调用intern()
更有效。事实上,在某些情况下,即使是临时字符串也可能是最有效的解决方案。为什么在您的示例中readFromFile().intern()
返回false
?它可以是其他地方引用的字符串文本形式的同一个“foo”
对象。似乎您的问题来自错误的假设。字符串池中的条目不是在类加载时创建的。它们是在ldc
指令的第一个分辨率下惰性创建的。所以,绝对有可能