Java字符串和字符串池

3
public String makinStrings() {
   String m = "Fred47";
   String s = "Fred";
   s = s + "47";
   s = s.substring(0);
   return s.toString();
} 

这段代码创建了多少个对象?

我进行了一个简单的测试:

public static void main(String[] args) {
   String m = "a";
   m += "bc";
   String s1 = "mabc".substring(1);
   String s2 = "abc";

   System.out.println(m == "abc");
   System.out.println(m == s1);
   System.out.println(m == s2);
   System.out.println(s1 == s2);
}

如果m,s1,s2指向同一对象(“abc”),那么结果不应该是“true, true, true, true”吗?但实际结果却是“false, false, false, false”!
2个回答

6
如果那种情况下,结果是true - 但ms1s2都指向不同的字符串。对于常量字符串表达式,自动执行内部化,并且可以通过调用intern方法显式调用,但对于字符串连接和子字符串,不会自动发生。
在Sun的Java 7实现中,x.substring(0)实际上会返回相同的引用(x),但我不认为API保证这一点。
看看你的例子:
public String makinStrings() {
   String m = "Fred47";
   String s = "Fred";
   s = s + "47";
   s = s.substring(0);
   return s.toString();
}

前两行要求在内存中有两个字符串,但我不知道确切的对象创建时间。一旦它们被创建,它们就会保留下来 - 因此再次调用makinStrings将不会在这两行中创建任何更多的字符串。

字符串连接创建一个新的字符串对象。

在我查看的实现中,substring调用不会创建新的字符串对象 - 但它可能会。

调用s.toString()不会创建新的字符串(这在JavaDoc中有说明)。


0
不,仅仅因为两个字符串相等并不意味着它们的引用相等。
编译器会将一些字符串进行内部处理以节省空间,所以如果你尝试:
String s1 = "abc";
String s2 = "abc";

那么 s1 == s2 将为 true,但这是一个特例而不是一般规则。通常在运行时生成的字符串默认情况下不共享同一引用。


我原本期望如果字符串池中存在相应的对象,那么新的字符串对象也会从字符串池中获取。自Java 5.0以来,数字(如Integer、Byte等)被缓存(至少是小数字),并在从字符串解析时重复使用。我原本期望字符串也是这样,但似乎并非如此... - Robert
我怀疑这是因为在字符串上进行空间/性能权衡不值得,而在整数上却值得,因为装箱时可能会得到大量相等的对象。但是你不应该依赖当前的行为-它可能会在未来的实现中发生改变。 - Mark Byers
@Mark - 正确...将字符串进行内部化是昂贵的,但查找整数对象是否已经存在则很便宜。 - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接