Stirng类,一个有故事的类 | Java Debug 笔记

196 阅读2分钟

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看活动链接

一 故事背景

乐乐工作时有时候会和同事探讨一些技术问题,今天同事抛出了一个问题

String s ="str"String s = new String("str")

他们有什么区别,让乐乐觉得对Stting类的了解还不够,于是准备对String类重新认识一遍

二 分析开始

简单的问题往往很复杂,乐乐觉得说的就是String,那就看看为什么他很简单,又为什么他很复杂?从源码开始扒

  1. 源码

    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堆内存中,下面我们通过代码验证

  2. 代码验证

String str5 = new String("杨")+new String("乐乐");
System.out.println(str5== str5.intern()  );  //true

String 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的区别,后来查验 的确如此。