一 故事背景
乐乐工作时有时候会和同事探讨一些技术问题,今天同事抛出了一个问题
String s ="str" 和 String s = new String("str")
他们有什么区别,让乐乐觉得对Stting类的了解还不够,于是准备对String类重新认识一遍
二 分析开始
简单的问题往往很复杂,乐乐觉得说的就是String,那就看看为什么他很简单,又为什么他很复杂?从源码开始扒
源码
public final class String
implements java.io.Serializable, Comparable, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; ... 这个类老长了,不过你一定看到了`final`,为啥要记这个,因为面试时会问,相加之后是几个对象。 `String s ="str"`和 `String s = new String("str")`有没有区别,你可能说没有,但是现实是有。 啥区别?`String s ="ss"` 是在编译时,放到常量池中的 `String s = new String("str")` 是在运行期,做了两件事,第一放到常量池,第二放到head堆内存中,下面我们通过代码验证
- 代码验证
String str5 = new String("杨")+new String("乐乐");
System.out.println(str5== str5.intern() ); //trueString str6 = new String("杨乐乐");
System.out.println(str6== str6.intern() ); //false先说下面的 下面的false是因为
new String
的时候创建了两个对象一个对象放到了堆内存head中一个放到了常量池中,然后 执行str6.intern
方法实际上是先去常量池中找是否有“杨乐乐”,如果有就返回杨乐乐,最终他们进行比较,但是str6指向的是head堆内存,而str6.intern指向的是常量池,就返回false了,然后说上面的就比较复杂,复杂在intern()
这个方法。
首先 String str5 = new String("杨")+new String("乐乐");
做了几件事,新建一个“杨”放在了head及常量池 又新建一个 “乐乐”放在head及常量池,
最终str5成为了new String(“杨乐乐”)
的引用
而str5.intern()
实际上是 先在常量池中找“杨乐乐” ,但是他没有找到
没有找到后 “他就在常量池中增加了一个 new String(“杨乐乐”)
的引用 ” 最终str6== str6.intern()
比较了两个引用相同,所以返回true。
然后我和同事说网上的答案有问题,网上的关于intern方法的解答
intern方法的用途
关于字符串String中的intern方法,是当前的字符对象(通过new出来的对象)可以使用intern方法从常量池中获取,
如果常量池中不存在该字符串,那么就新建一个这样的字符串放到常量池中。
这里面没有说引用,同事说这个是jdk1.6和jdk1.7的区别,后来查验 的确如此。