V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zpxshl
V2EX  ›  Java

请教 Java 关于 string 所存位置的题,很有趣(懵逼)的现象。

  •  
  •   zpxshl · 2019-01-20 21:25:02 +08:00 · 2761 次点击
    这是一个创建于 1915 天前的主题,其中的信息可能已经有所发展或是发生改变。

    String s0 = new StringBuilder("漠").append("然").toString(); System.out.println(s0 == s0.intern());

    String s1 = new StringBuilder("漠").append("然").toString(); System.out.println(s1 == s1.intern());

    //true false

    本渣渣研究了一天 string 相关文章,越看越懵逼。求大佬赐教。

    11 条回复    2019-01-21 19:07:58 +08:00
    lwj871731342
        1
    lwj871731342  
       2019-01-20 21:35:58 +08:00
    一个渣渣的猜测:
    第一次调用 intern 的时候将其放入了常量池,这时候和 s0 的引用相同
    第二次调用 intern 的时候找到了之前 s0 放入常量池的那个字符串的引用,这时的引用和 s1 的引用不同

    没有确切研究过...期待大佬的正确回答
    shalk
        2
    shalk  
       2019-01-20 21:38:54 +08:00
    对于你这个问题,你查询以下 intern 方法的说明。
    因为 intern 方法是 native 方法,所以要看底层实现有关,java 版本不同会有所不同
    网上有很多文章
    everwanna
        3
    everwanna  
       2019-01-20 21:41:18 +08:00 via iPhone
    判断字符串是否相等用 equal, == 只能判断引用和数值是否相等。
    字符串的存储专门做了优化,相同的字符串在内存中尽量用复用,但并不保证只有一个
    zsh1995
        4
    zsh1995  
       2019-01-20 21:41:41 +08:00
    调用 intern 时,如果在内部的 string pool 已经存在相同的 string 时,则返回 pool 中的值,否则把当前 string 放入 pool,并返回自身。
    第一次调用时,"漠然"不存在,所以将它放入 string pool,s0 等于 s0.intern()。
    第二次调用时,"漠然"已存在,s1.intern() 返回的是 string pool 中的值,即 s0。
    BBCCBB
        5
    BBCCBB  
       2019-01-20 21:42:30 +08:00
    s1.intern() 返回的是 s0 的地址,而 s1 是堆里一个新的`漠然`的地址。 仅供参考
    zpxshl
        6
    zpxshl  
    OP
       2019-01-20 21:44:33 +08:00
    @zsh1995 大哥注意一下,s0 = new StringBuilder("漠").append("然").toString(); 这时候没调用 intern 方法。 但是输出的结果证明了此时 s0 已经是 pool 里面的值。
    zpxshl
        7
    zpxshl  
    OP
       2019-01-20 21:46:01 +08:00
    @zsh1995 我的是 jdk1.8,网上大部分文章都看了,没有合理的解释。
    String sss = new StringBuilder("a").append("b").toString();
    System.out.println(sss == sss.intern()); // true
    个人偏向和 StringBuilder.toSting() 有关,同样是 native 方法。
    难道是 StringBuilder.toString 在 string 不在 pool 时会将其加入 pool,并返回 pool 的值。在 string 已经在 pool 时,反而不返回 pool 的值?
    zpxshl
        8
    zpxshl  
    OP
       2019-01-20 21:51:24 +08:00
    @BBCCBB @everwanna @lwj871731342 @shalk @zsh1995
    感谢各位大佬回复。已经找到答案。
    jdk1.7 后:string pool 存的是 string 的引用(而非 string 本身)。intern 返回的是该 string 对象第一次出现的位置(在 Heap 中)。 实在惭愧,研究了一天没想到答案,一来 v 站问就很快知道了。。。
    zhuawadao
        9
    zhuawadao  
       2019-01-21 09:22:55 +08:00
    我查了 1.8 的 API:
    当调用 intern 方法时,如果池已经包含与 equals(Object)方法确定的相当于此 String 对象的字符串,则返回来自池的字符串。 否则,此 String 对象将添加到池中,并返回对此 String 对象的引用。
    这就是答案吧
    payboy
        10
    payboy  
       2019-01-21 17:14:54 +08:00   ❤️ 1
    String s0 = new StringBuilder("漠").append("然").toString();//s0 指向堆中引用“漠然”
    s0.intern();//java7:因常量池不存在“漠然”字符串对象,存储堆中“漠然”的引用并返回
    String s1 = new StringBuilder("漠").append("然").toString();//s1 指向堆中引用“漠然”,与 s0 指向引用不是同一个
    s1.intern();//java7:因常量池已存在“漠然”字符串对象引用,返回引用,与 s0 指向引用是同一个
    zpxshl
        11
    zpxshl  
    OP
       2019-01-21 19:07:58 +08:00 via Android
    @payboy 是的。感谢回答
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3062 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 14:50 · PVG 22:50 · LAX 07:50 · JFK 10:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.