请教 Java 关于 string 所存位置的题,很有趣(懵逼)的现象。

2019-01-20 21:25:02 +08:00
 zpxshl

String s0 = new StringBuilder("漠").append("然").toString(); System.out.println(s0 == s0.intern());

String s1 = new StringBuilder("漠").append("然").toString(); System.out.println(s1 == s1.intern());

//true false

本渣渣研究了一天 string 相关文章,越看越懵逼。求大佬赐教。

2963 次点击
所在节点    Java
11 条回复
lwj871731342
2019-01-20 21:35:58 +08:00
一个渣渣的猜测:
第一次调用 intern 的时候将其放入了常量池,这时候和 s0 的引用相同
第二次调用 intern 的时候找到了之前 s0 放入常量池的那个字符串的引用,这时的引用和 s1 的引用不同

没有确切研究过...期待大佬的正确回答
shalk
2019-01-20 21:38:54 +08:00
对于你这个问题,你查询以下 intern 方法的说明。
因为 intern 方法是 native 方法,所以要看底层实现有关,java 版本不同会有所不同
网上有很多文章
everwanna
2019-01-20 21:41:18 +08:00
判断字符串是否相等用 equal, == 只能判断引用和数值是否相等。
字符串的存储专门做了优化,相同的字符串在内存中尽量用复用,但并不保证只有一个
zsh1995
2019-01-20 21:41:41 +08:00
调用 intern 时,如果在内部的 string pool 已经存在相同的 string 时,则返回 pool 中的值,否则把当前 string 放入 pool,并返回自身。
第一次调用时,"漠然"不存在,所以将它放入 string pool,s0 等于 s0.intern()。
第二次调用时,"漠然"已存在,s1.intern() 返回的是 string pool 中的值,即 s0。
BBCCBB
2019-01-20 21:42:30 +08:00
s1.intern() 返回的是 s0 的地址,而 s1 是堆里一个新的`漠然`的地址。 仅供参考
zpxshl
2019-01-20 21:44:33 +08:00
@zsh1995 大哥注意一下,s0 = new StringBuilder("漠").append("然").toString(); 这时候没调用 intern 方法。 但是输出的结果证明了此时 s0 已经是 pool 里面的值。
zpxshl
2019-01-20 21:46:01 +08:00
@zsh1995 我的是 jdk1.8,网上大部分文章都看了,没有合理的解释。
String sss = new StringBuilder("a").append("b").toString();
System.out.println(sss == sss.intern()); // true
个人偏向和 StringBuilder.toSting() 有关,同样是 native 方法。
难道是 StringBuilder.toString 在 string 不在 pool 时会将其加入 pool,并返回 pool 的值。在 string 已经在 pool 时,反而不返回 pool 的值?
zpxshl
2019-01-20 21:51:24 +08:00
@BBCCBB @everwanna @lwj871731342 @shalk @zsh1995
感谢各位大佬回复。已经找到答案。
jdk1.7 后:string pool 存的是 string 的引用(而非 string 本身)。intern 返回的是该 string 对象第一次出现的位置(在 Heap 中)。 实在惭愧,研究了一天没想到答案,一来 v 站问就很快知道了。。。
zhuawadao
2019-01-21 09:22:55 +08:00
我查了 1.8 的 API:
当调用 intern 方法时,如果池已经包含与 equals(Object)方法确定的相当于此 String 对象的字符串,则返回来自池的字符串。 否则,此 String 对象将添加到池中,并返回对此 String 对象的引用。
这就是答案吧
payboy
2019-01-21 17:14:54 +08:00
String s0 = new StringBuilder("漠").append("然").toString();//s0 指向堆中引用“漠然”
s0.intern();//java7:因常量池不存在“漠然”字符串对象,存储堆中“漠然”的引用并返回
String s1 = new StringBuilder("漠").append("然").toString();//s1 指向堆中引用“漠然”,与 s0 指向引用不是同一个
s1.intern();//java7:因常量池已存在“漠然”字符串对象引用,返回引用,与 s0 指向引用是同一个
zpxshl
2019-01-21 19:07:58 +08:00
@payboy 是的。感谢回答

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/528895

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX