String的赋值操作,intern,==等的关系
Posted 软件猫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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- String str1 = new String("SEU")+ new String("Calvin");
- System.out.println(str1.intern() == str1);
- System.out.println(str1 == "SEUCalvin");
本人JDK版本1.8,输出结果为:
[java] view plain copy
- true
- true
- String str2 = "SEUCalvin";//新加的一行代码,其余不变
- String str1 = new String("SEU")+ new String("Calvin");
- System.out.println(str1.intern() == str1);
- System.out.println(str1 == "SEUCalvin");
[java] view plain copy
- false
- 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;
以上是关于String的赋值操作,intern,==等的关系的主要内容,如果未能解决你的问题,请参考以下文章