老问题重提,关于String类型

richard_2010 2011-03-14 01:08:05
String a = "tes";
String b = a + "t";
这个引用b指向的内容为"test"么?从下面的测试结果看来不是这样:
String c = new String("test");
System.out.println(b == c.intern());//输出为false
我们知道String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,
如果有则返回一个引用,没有则添加自己的字符串进进入常量池。

从上面推测b指向的内容并非为"test",不然的话b == c.intern()应该输出true才对。
那么,引用b到底是一个什么东西?
从网上有人说的是编译器在编译时将String b = a + "t";
转化成String b = new StringBuffer("tes").append("t").toString();
也就是b指向的其实是堆上StringBuffer所占的内存单元,那么测试:
System.out.println(b.intern == c.intern());//输出为true

以上为我猜测,请问我的猜测对吗?欢迎了解JVM机制的童鞋一起讨论。
...全文
257 26 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
wuchuke 2011-03-14
  • 打赏
  • 举报
回复
我来试着解释一下,看对不对:
String b = a + "t";
String c = new String("test");
System.out.println(b == c.intern());

此时常量池中没有"test",也就是b的内容"test"不是在常量池中,而c.intern()执行之后,在常量池中创建了"test",并返回它,当然b != c.intern()。

System.out.println(b.intern() == c.intern());
当然输出true,因为b和c的内容相同,b.intern()和c.intern()返回的都是常量池中的test。

也就是楼主的推测是对的:
String b = a + "t";不会在常量池中生成一个"test"。
richard_2010 2011-03-14
  • 打赏
  • 举报
回复
问题解决,结贴去。
谢谢ls所有回复的人,不管正确or错误
eXeSP 2011-03-14
  • 打赏
  • 举报
回复
你的猜测差不多是对的,有一点是
在JDK1.5之后,字符串拼接是调用StringBuilder的appen方法。

b == c.intern()
一个在堆中,一个在字符串池中,内存地址显然不相等。
richard_2010 2011-03-14
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 dracularking 的回复:]

是,string concatenation生成的串不是interned,它就相当于StringBuffer或StringBuilder append再toString

All literal strings and string-valued constant expressions are interned.
[/Quote]

恩,这和我猜的差不多,我知道答案了,thanks。

BTW,论坛里面还是那么多浮躁的人啊
richard_2010 2011-03-14
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 dracularking 的回复:]

再通过这个验证:
Java code

String b = "tes" + "t";
System.out.println(b.intern() == b);



结果为true
[/Quote]

这个是因为"tes" + "t"在编译时就能确定的,所以直接被编译成"test"放在常量池
dracularking 2011-03-14
  • 打赏
  • 举报
回复
我13楼说的 漏了说明例外情况
richard_2010 2011-03-14
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 followme_1987 的回复:]

b == c.intern()你这是比较两个String对象,必然不相等!跟b里的内容是什么没有关系,跟是不是池里的也没有关系。而且b里的内容就是“test”! 你要用b.equals(c.intern())就是true了。跟JVM也没什么关系。建议还是先想想== 和equals方法两种不同的比较方式...........
[/Quote]

b == c.intern()你这是比较两个String对象,必然不相等。是吗?
littleJP 2011-03-14
  • 打赏
  • 举报
回复
不是的啊
c.intern()返回池中的字符串,那池中的字符串就相当于是常量"test",也就是说相当于双引号生成的,而
b=a + "t"; 很明显相当于new生成的,生成一个新对象,两个对象不是同一个,你用==比较当然就是false了。
dracularking 2011-03-14
  • 打赏
  • 举报
回复
上面是string值的常量表达式,属于例外吧
dracularking 2011-03-14
  • 打赏
  • 举报
回复
再通过这个验证:

String b = "tes" + "t";
System.out.println(b.intern() == b);


结果为true
dracularking 2011-03-14
  • 打赏
  • 举报
回复
操作符+用于字符串时进行了重载,基本可以推测是借用了String的concat方法


public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}

该方法就是返回堆中新生成对象的,而不是the interned one

从定义上讲:
String a = "tes";
String b = a + "t";

a是literal,而b就不是literal,也不是string valued constant expression,因为a不是constant
详见:jls §3.10.5:http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#101083
azun888 2011-03-14
  • 打赏
  • 举报
回复
实践出真知,你可以在自己的机器上敲一敲吗,看看结果
Ganymede 2011-03-14
  • 打赏
  • 举报
回复
再补充一下,无论有多少String对象 只要内容一样,那么池中有且只有一份该对象,所以b.intern() 和c.intern()返回的池中的对象是同一个。
dracularking 2011-03-14
  • 打赏
  • 举报
回复
是,string concatenation生成的串不是interned,它就相当于StringBuffer或StringBuilder append再toString

All literal strings and string-valued constant expressions are interned.
Ganymede 2011-03-14
  • 打赏
  • 举报
回复
b == c.intern()你这是比较两个String对象,必然不相等!跟b里的内容是什么没有关系,跟是不是池里的也没有关系。而且b里的内容就是“test”! 你要用b.equals(c.intern())就是true了。跟JVM也没什么关系。建议还是先想想== 和equals方法两种不同的比较方式...........
richard_2010 2011-03-14
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 ilrxx 的回复:]

Java code

String b = "test";
System.out.println(b == c.intern());//输出为true


说明b和c都是在一个常量池中,lz的举例和分析应该是没错的。
[/Quote]

输出为真不代表c也在常量池。。。。c.intern()指向的是常量池里面的一个引用,c仍然在堆里面老实呆着
richard_2010 2011-03-14
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 coolfatman 的回复:]

真无聊,还有人在谈这个。
[/Quote]

是够无聊,我相信你并没有弄懂这里面和JVM有关的知识。
richard_2010 2011-03-14
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 runer 的回复:]

唉,这个问题实在不想再说啥了

给你转一个文章,说的蛮透彻的



Java运行环境有一个字符串池,由String类维护。执行语句String str="abc"时,首先查看字符串池中是否存在字符串"abc",如果存在则直接将"abc"赋给str,如果不存在则先在字符串池中新建一个字符串"abc",然后再将其赋给str。执行语句String str=new String("abc")……
[/Quote]

谢谢,你转的东西不适合我提出来的问题
dong_very_good 2011-03-14
  • 打赏
  • 举报
回复
个人认为:
String b = a + "t"会创建一个新的String对象,b对象的值不变还是"tes";
而String b = new StringBuffer("tes").append("t").toString()这种方法创建一个字符串放在b对象中,概念不同。
Coolfatman 2011-03-14
  • 打赏
  • 举报
回复
真无聊,还有人在谈这个。
加载更多回复(4)

62,634

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧