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

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

  •  
  •   zpxshl · 27 天前 · 1005 次点击

    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
        1
    lwj871731342   27 天前
    一个渣渣的猜测:
    第一次调用 intern 的时候将其放入了常量池,这时候和 s0 的引用相同
    第二次调用 intern 的时候找到了之前 s0 放入常量池的那个字符串的引用,这时的引用和 s1 的引用不同

    没有确切研究过...期待大佬的正确回答
        2
    shalk   27 天前
    对于你这个问题,你查询以下 intern 方法的说明。
    因为 intern 方法是 native 方法,所以要看底层实现有关,java 版本不同会有所不同
    网上有很多文章
        3
    everwanna   27 天前 via iPhone
    判断字符串是否相等用 equal, == 只能判断引用和数值是否相等。
    字符串的存储专门做了优化,相同的字符串在内存中尽量用复用,但并不保证只有一个
        4
    zsh1995   27 天前
    调用 intern 时,如果在内部的 string pool 已经存在相同的 string 时,则返回 pool 中的值,否则把当前 string 放入 pool,并返回自身。
    第一次调用时,"漠然"不存在,所以将它放入 string pool,s0 等于 s0.intern()。
    第二次调用时,"漠然"已存在,s1.intern() 返回的是 string pool 中的值,即 s0。
        5
    BBCCBB   27 天前
    s1.intern() 返回的是 s0 的地址,而 s1 是堆里一个新的`漠然`的地址。 仅供参考
        6
    zpxshl   27 天前
    @zsh1995 大哥注意一下,s0 = new StringBuilder("漠").append("然").toString(); 这时候没调用 intern 方法。 但是输出的结果证明了此时 s0 已经是 pool 里面的值。
        7
    zpxshl   27 天前
    @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 的值?
        8
    zpxshl   27 天前
    @BBCCBB @everwanna @lwj871731342 @shalk @zsh1995
    感谢各位大佬回复。已经找到答案。
    jdk1.7 后:string pool 存的是 string 的引用(而非 string 本身)。intern 返回的是该 string 对象第一次出现的位置(在 Heap 中)。 实在惭愧,研究了一天没想到答案,一来 v 站问就很快知道了。。。
        9
    zhuawadao   27 天前
    我查了 1.8 的 API:
    当调用 intern 方法时,如果池已经包含与 equals(Object)方法确定的相当于此 String 对象的字符串,则返回来自池的字符串。 否则,此 String 对象将添加到池中,并返回对此 String 对象的引用。
    这就是答案吧
        10
    payboy   26 天前   ♥ 1
    String s0 = new StringBuilder("漠").append("然").toString();//s0 指向堆中引用“漠然”
    s0.intern();//java7:因常量池不存在“漠然”字符串对象,存储堆中“漠然”的引用并返回
    String s1 = new StringBuilder("漠").append("然").toString();//s1 指向堆中引用“漠然”,与 s0 指向引用不是同一个
    s1.intern();//java7:因常量池已存在“漠然”字符串对象引用,返回引用,与 s0 指向引用是同一个
        11
    zpxshl   26 天前 via Android
    @payboy 是的。感谢回答
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2147 人在线   最高记录 4346   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 16ms · UTC 07:26 · PVG 15:26 · LAX 23:26 · JFK 02:26
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1