泳池啥时候换?
Posted
技术标签:
【中文标题】泳池啥时候换?【英文标题】:When does the pool change?泳池什么时候换? 【发布时间】:2013-01-05 00:55:57 【问题描述】:我有两个问题:
public static void main(String[] args)
String s1 = "bla";
String s2 = "b" +"l" + "a";
String s3 = "b".concat("l").concat("a");
if(s1 == s2)
System.out.println("Equal");
else
System.out.println("Not equal");
if(s1 == s3)
System.out.println("Equal");
else
System.out.println("Not equal");
为什么s1
和s2
指向同一个对象,而s1
和s3
却没有? (没有使用new
关键字)。
如果我从用户那里得到一个字符串并将这些行添加到上面的代码中:
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String name=in.readLine();
if(name.equals("test"))
s1 = s1 + "xyz";
如果用户输入xyz
,程序将打印Not equal
,当用户输入另一个东西时,程序输出Equal
。这是否意味着池会随着整个程序的执行而改变?优化器是否在编译时工作并在runtime
中继续工作?
【问题讨论】:
【参考方案1】:为什么 s1 和 s2 指向同一个对象,而 s1 和 s3 不是吗? (没有使用 new 关键字)。
由于Java中的String
是Immutable
,所以字符串类的任何方法都会返回一个新的String对象(不过也有一些例外——一个是substring
方法)。因此,concat
方法创建了一个新字符串,该字符串进入 Heap,并且不会添加到常量池中。
就s1
和s2
而言,这两个字符串在编译 时都是已知的,因此它们是相同的字符串文字。
注意第二个字符串中的连接操作:-
String s2 = "b" +"l" + "a";
在编译时求值,已知结果与第一个字符串相同,并在常量池中输入一个条目。
【讨论】:
【参考方案2】:有时(当编译器很明显 String 的值在运行时是什么时)编译器使用字符串池,在其他情况下则不使用。
其实你的代码不应该依赖于使用或不使用池的事实。
你不能总是运行 main,所以如果你想看看你的 String 是否是从池中使用的,你可以用 javap 反编译代码,清单相对不言自明。
【讨论】:
【参考方案3】:为什么 s1 和 s2 指向同一个对象,而 s1 和 s3 却没有? (没有使用 new 关键字)。
因为连接发生在编译时,因此完成的字符串会像第一个示例一样进入常量池。这是编译器“已知”的特殊情况。这实际上意味着长字符串,以这种方式连接多行,仍然可以获得与简单字符串常量相同的性能改进。
在第二个示例中,您在运行时执行计算,因此它不会成为常量池的一部分。
但是请注意,在 JLS 中,字符串常量池中可以和不可以进入的细节故意保持模糊,因此不同的实现可能会以不同的方式进行优化。它指定了一些关于必须进入其中的规则,但不要依赖这种行为在实现之间保持一致。
【讨论】:
以上是关于泳池啥时候换?的主要内容,如果未能解决你的问题,请参考以下文章