我的问题是关于 Java 处理字符串文字的方式。从 Java 语言规范 (JLS) 可以清楚地看出,字符串文字是隐式驻留的 - 换句话说,在堆的字符串常量池部分中创建的对象,与调用
new String("whatever")
时创建的基于堆的对象形成对比
.
似乎与 JLS 所说的不一致的是,当使用 String 连接与强制转换的常量 String 类型(根据 JLS 应将其视为常量 String)创建新 String 时,显然 JVM 正在创建一个new String 对象而不是隐式地实习它。我很欣赏有关此特定行为以及这是否是特定于平台的行为的任何解释。我正在 Mac OSX Snow Leopard 上运行。
public class Test
{
public static void main(String args[])
{
/*
Create a String object on the String constant pool
using a String literal
*/
String hello = "hello";
final String lo = "lo"; // this will be created in the String pool as well
/*
Compare the hello variable to a String constant expression
, that should cause the JVM to implicitly call String.intern()
*/
System.out.println(hello == ("hel" + lo));// This should print true
/*
Here we need to create a String by casting an Object back
into a String, this will be used later to create a constant
expression to be compared with the hello variable
*/
Object object = "lo";
final String stringObject = (String) object;// as per the JLS, casted String types can be used to form constant expressions
/*
Compare with the hello variable
*/
System.out.println(hello == "hel" + stringObject);// This should print true, but it doesn't :(
}
}
编译时常量表达式中不允许转换为
Object
。唯一允许的强制转换是 String
和原语。 JLS(Java SE 7 版)第 15.28 节:
(实际上还有第二个原因。
object
不是final
,所以不可能被视为常量。“原始类型或类型String
的变量,即final
并通过编译初始化-时间常量表达式(第 15.28 节),称为常量变量。”——第 4.12.4 节。)
似乎因为您在这里引用了一个对象
final String stringObject = (String) object;
,这不再是“编译时”常量,而是“运行时”常量。 here 中的第一个示例通过以下部分回避了它:
String s = "lo";
String str7 = "Hel"+ s;
String str8 = "He" + "llo";
System.out.println("str7 is computed at runtime.");
System.out.println("str8 is created by using string constant expression.");
System.out.println(" str7 == str8 is " + (str7 == str8));
System.out.println(" str7.equals(str8) is " + str7.equals(str8));
字符串 str7 是在运行时计算的,因为它引用了另一个不是文字的字符串,因此根据该逻辑,我假设尽管您将
stringObject
定为最终的面,但它仍然引用一个对象,因此无法在编译时计算.
从 java lang 规范这里,它指出:
“当结果不是编译时常量表达式(第 15.28 节)时,字符串连接运算符 +(第 15.18.1 节)隐式创建一个新的 String 对象。”
我找不到任何可以使用强制类型转换的示例,除了这个非常非常糟糕的示例:
System.out.println(hello == "hel" + ( String ) "lo");
这几乎没有任何逻辑用途,但可能由于上述情况而包含了有关字符串转换的部分。