String的赋值操作,intern,==等的关系

很多人可能都会对String的==操作感到非常迷茫,这个的话, 首先我们来看一下这个规律。

jdk1.6

1)如果对String变量赋值字面量,比如String a = “abcdef”,那么这个时候会首先到方法区的常量池中间找abcdef是否存在,如果存在,则返回这个对象的引用。如果不存在,则首先在常量池中创建这个对象,再返回这个对象的引用。

2)如果是new,则会在堆中创建这个对象。如果对这个new创建的对象使用intern,则会在方法区中创建一个对象。比如String b = new String(“123456”),在堆中创建一个String对象b,b.intern(),去方法区的常量区查看是否存在123456,不存在创建,存在则不创建,然后返回这个常量区的123456字符串的引用(不修改b)

3)==比较的是地址,而不是内容,equals比较的是内容(对于字符串而言)


jdk1.7,方法区的常量区已经放到了堆内存中了,因此有区别,区别主要是在intern里面。

1)如果对String变量赋值字面量,若这个字面量是第一次使用,这个和jdk1.6类似。但是有一个区别,区别就是如果常量池存在了这么个对象,那么可能返回的是一个堆内存对象的引用,原因就是intern方法,具体原因往下看。

2)对于new创建的字符串,比如String b = new String("abcdefgh"),会在堆中创建这么一个对象,同时也会在常量池创建abcdefgh字符串对象。这个时候如果你调用b.intern(),那么几乎是没有用处的,这个b.intern()的作用仅仅是检查常量池是否存在abcdefgh这个字符串,这里是存在的,直接返回常量池中字符串对象abcdefgh的引用即可。如果不存在呢?这个地方要注意了!它会把b的引用复制到常量池,然后返回b的引用(jdk1.6是在常量池直接创建一个对象),这个时候就会产生一种效果。什么效果呢?往下看一个具体的例子

什么都先不说,先看下面这个引入的例子:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. String str1 = new String("SEU")+ new String("Calvin");      
  2. System.out.println(str1.intern() == str1);   
  3. System.out.println(str1 == "SEUCalvin");  

本人JDK版本1.8,输出结果为:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. true  
  2. true  
再将上面的例子加上一行代码:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. String str2 = "SEUCalvin";//新加的一行代码,其余不变  
  2. String str1 = new String("SEU")+ new String("Calvin");      
  3. System.out.println(str1.intern() == str1);   
  4. System.out.println(str1 == "SEUCalvin");   
再运行,结果为:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. false  
  2. false  
这个例子呢,是从别的文章摘抄过来的,不过他没有解释原因,我来帮他解释下吧。

jdk1.8和jdk1.7是非常类似的。第一次运行的结果是true,true,为什么呢?

先看第一段代码,第一行String str1 = new String("SEU")+new String("Calvin");这里jvm作了什么工作呢?jvm在堆中创建了3个对象,内容为SEU和内容为Calvin以及内容为SEUCalvin的对象。同时,在常量池中创建了两个对象,SEU和Calvin。好,那么str1.intern()==str1为什么是true呢?回到我们前面所讲的加粗内容:它会把b的引用复制到常量池,然后返回b的引用,这个时候就会产生一种效果。 来看,str1的内容SEUCalvin在常量池是不存在的,于是,我们将str1的引用复制到常量池,并返回这个引用,也就是返回str1,那么str1和str1相等吗?当然相等。再看第三行,str1==“SEUCalvin”,这里也是true,为什么呢?按照jdk1.6,这里应该是false啊。首先你要明白,“SEUCalvin”这是个字符串常量,它会到常量池中去查找是否存在这么个对象,结果发现存在(第二行的str1.intern()在常量池创建了这么一个引用),然后返回了这么个引用,这个引用还是str1啊,所以还是true;

第二段代码为什么都变成了false了呢?首先我们要明白,==比较的都是地址,因此返回false肯定是地址不同,在分析之前,我们先看一个简单的例子:

String a = new String("ab1234rcdefgh");
System.out.println(a.intern()==a);
这里输出啥?如果你的回答是false,我可以恭喜你,前面理解的还不错,因为这里是的new String("ab1234rcdefgh")创建了两个对象,一个在堆中,一个在常量池中,因此,a.intern()返回的是一个在常量池的字符串对象的引用,而不是a引用本身,因此这里的输出是false;

好,我们来看第二段代码。第二段代码就是多了一行,String str2 = "SEUCalvin";这一行的作用可大了啊。看我们的jdk1.7的规律的第一行,是不是说了,如果第一次使用这个字面量,我们会在常量池中创建这么个对象对吧。那么这个对象已经创建了,后面的new操作也就不会在常量池创建对象了,同时intern操作也不会将引用赋值过去了,而是检查发现这个字符串已经在常量池了,那么直接返回这个字符串的引用就行了。所以,str1.intern()返回的实际上是str2,“SEUCalvin”也是str2,所以都是ifalse了。

再来看一个简单的例子加深理解。

String c = new String("123")+new String("456");
String d = "123456";
System.out.println(c==d);
System.out.println(c.intern()==d);

这里的输出是false;true。

原因?c对象的创建伴随着在堆中创建123,456,123456对象,同时也伴随着在常量池中创建123,456对象。d的创建伴随着在常量池闯将123456对象。因此c和d是不同的引用,是不同的地址。c.intern()操作返回的地址就是d啊,这个很清楚了啊。intern()操作回去常量池查找是否存在这么个字符串123456,存在的直接返回引用。不存在,在jdk7中是要将这个字符串对象的引用复制过去(jdk1.6是在常量池创建字符串对象)。而这里是存在的,返回的引用就是d,所以肯定是true;








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值