java中String.intern问题

getYang 发布于 2016/09/19 10:50
阅读 554
收藏 0
String s2 = new String("abc");
s2.intern(); String s1 = "abc";
System.out.println(s1 == s2); //false  这个和下面有什么不同  
String s3 = new String("bug") + new String("yang");
String s4 =  s3.intern(); //1 String s5 = "bugyang";
System.out.println(s5 == s3); //true  这个为什么true呢
加载中
0
逝水fox
逝水fox

intern()是返回字符串常量池中的值相同的字符串(如果没有就在常量池添加后返回)。

返回的意思是,要用返回值,不然这调用除了消耗常量池没有任何意义

getYang
getYang
这个我是知道的,我是想知道,这2个例子结果为什么不同。。
0
xpbob
xpbob
==比较的是地址,调用intern后会返回常量池的地址,常量池里有相同的字符串就返回那个地址,没有就新建一个再返回,所以最后比较地址的时候就是相同的
xpbob
xpbob
回复 @getYang : http://brokendreams.iteye.com/blog/2260870 原来是jvm的分区和实现不一样,这个里面解析了native的代码
xpbob
xpbob
回复 @getYang : 这个稍微有点不一样,+号sunjdk会解析成stringbuilder最后toString,用的构造函数是String(char[]),用char[]构建的对象和String(String)的对象还不大一样。只要是上面的那种情况,调用intern方法,引用指向也会跟着变
getYang
getYang
这个我是知道的,我是想知道,这2个例子为什么不同。。
0
kurumi
kurumi

new和直接赋值肯定不等,而s3赋值其实相当于数s3=“bug”+“yang”,和两个new其实没什么关系


kurumi
kurumi
回复 @慢慢成长 : 哈哈,还真是,你这个还真看不懂了
慢慢成长
慢慢成长
【s3赋值其实相当于数s3=“bug”+“yang”】 这个不对吧,String s3 = new String("bug") + new String("yang"); 这个是两个引用类型+,不会存到常量池的
0
汉唐
汉唐

给你推荐两篇文章看一下 

http://calvin1978.blogcn.com/articles/string-intern.html

http://www.jianshu.com/p/0d1c003d2ff5

0
zqq90
zqq90
楼主这代码是写在了 Method 还是 static{} 里面,
String s5 = "bugyang";
如果是 Method 这一步应该 感觉已经会让其出现在池里面, 按照直觉确实不该 s3 == s5
0
张国超0o0
张国超0o0

我是这样觉着,首先intern()方法是 如果看池中有该String就返回该String ,没有回加上该String,并返回;其次你第一个方法是直接返回而没有接收,而是那一个s2(也就是一个object)与一个String 进行“==”比较肯定会为false,第二个 s3 指向的 两个String的相加的引用,然后这是池中还没有”bugyang“,依据上面说的 调用intern方法会把池中加入该String并且返回该String,此时s5与s4应该是同一个String。不知道这样说可以吗?欢迎指正

getYang
getYang
谢谢~!
0
清尘V
清尘V

1、前提条件:abc已经存在常量池里了,所以s2.intern()其实并没有任何作用。s2指向的是对象创建的地址,s1是常量池里的地址,所以不等;

2、s3.intern()是把bugyang放入常量池,所以常量池里bugyang指向s3的地址;s5去常量池里寻找bugyang,间接的找到了s3,所以是相等的;


如果是jdk6  则两个都是不相等的,在7里,常量池移到了堆区,而非6的永久代了

参考文章:http://tech.meituan.com/in_depth_understanding_string_intern.html

慢慢成长
慢慢成长
这个讲的就比较清楚明了了
0
levis999
levis999
常量池保存的是在编译时能够确定下来的东西,new创建的不是常量,不能再编译时确定下来 

intern的作用是对上面常量池的补充,即虽然有些东西在编译的时候没有确定下来,但是后续想让他进入常量池,怎么办,就是这个鬼:intern

String s2 = new String("abc");//声明变量s2.并分配一块内存地址 内容是abc s2指向的地址是堆中地址
s2.intern(); //将abc这个值压入常量池
String s1 = "abc";//声明一个变量s1,指向的常量池中的地址,常量池中已经有常量“abc”,intern方法,画外音:“”直接引号包含的值都是放在常量池中。
System.out.println(s1 == s2); //false  这个和下面有什么不同  s1指向的是常量池的地址 s2指向的是堆中地址。

String s3 = new String("bug") + new String("yang");

就上面的这句代码如果改成: s3 = “bug” + “yang”;s3其实就是常量了,虽然用了+,但是编译的时候已经定下来了。

String s4 =  s3.intern(); //1 进入常量池,,,至于s4,这里跟他没关系。
String s5 = "bugyang";//指向常量池地址
System.out.println(s5 == s3); //true  这个为什么true呢,这样的话s3也是常量池,s5也是常量池,并且地址一样。


常量池,s1=“abc”  s2=“abc” 其实指的都是同一个地址,因为常量池中相同的值,只分配一个地址。


不知道说清楚了没有,其实java的书上开篇都写了,只是不同的翻译者对有些术语表述的不一样。

如有疑问:Q九七69699



levis999
levis999
回复 @慢慢成长 : s3.intern();因为这个方法,在这个方法之前,s3也是堆中地址
猫不贰
猫不贰
s3的引用应该是 stringBuilder append两个字符串之后,然后调用自身的toString返回的字符串对象。所以按道理说,s5和s3不是同一引用。不过令我奇怪的是在1.6以下的jdk里,s5==s3返回false.而1.7返回的是true。而这两个版本编译出的class文件没什么不同
levis999
levis999
intern这个方法的作用就是扩充常量池,将堆中的数据 写入常量池。 s3在没有经过intern方法前,是在堆中。你可以把这行注释掉,结果就是false
慢慢成长
慢慢成长
你说到 s2 是堆中的地址,那为什么 s3 就不是堆中的地址呢?
0
逝水fox
逝水fox

如果在JDK6运行此代码,第二项仍然会返回false。

区别在于JDK6及以下版本,字符串常量池在永久带中,所以intern()只能创建新的对象进永久带,而JDK7开始,字符串常量池移出永久带,所以intern()操作遇到新的对象只需在常量池记录原对象的引用即可,所以在JDK7以后的版本执行,s4 s3 s5都是同一个对象。

但看第一段代码,因为初始化s1的时候用到了常量"abc",所以在调用s1.intern()时,实际上常量池中已有了"abc"字符串,他就不会再记录s1的引用值。此时,s1引用本身仍处于常量池外。


返回顶部
顶部