四行代码的 Java Puzzle----老司机快来刷题解惑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ZiLong
V2EX    Java

四行代码的 Java Puzzle----老司机快来刷题解惑

  •  
  •   ZiLong 2017-09-25 11:27:34 +08:00 4501 次点击
    这是一个创建于 2948 天前的主题,其中的信息可能已经有所发展或是发生改变。
     String str1 = new StringBuilder("hel").append("lo").toString(); String str2 = new StringBuilder("ja").append("va").toString(); System.out.println(str1.intern() == str1); // true System.out.println(str2.intern() == str2); // false 

    百思不得琦姐,为什么这个输出一个是 true,一个是 false ?

    16 条回复    2017-09-25 23:12:58 +08:00
    zxyroy
        1
    zxyroy  
       2017-09-25 11:33:14 +08:00
    貌似和 string 长度有关,具体的我一时间查不到
    rozbo
        2
    rozbo  
       2017-09-25 11:44:19 +08:00
    很简单因为`java`这个字符串之前被初始化过。
    而另外一个没有。。
    hcymk2
        3
    hcymk2  
       2017-09-25 11:57:19 +08:00
    运行环境也不说个。
    yankebupt
        4
    yankebupt  
       2017-09-25 11:59:43 +08:00
    猜测有可能是因为"java"因为常用所以池中已有,append 出来的那个并不是第一个生成的所以 intern 不能指向自身...
    据说不是纯引号的 literal 字符串用==会比较 reference 而不是 intern 的值,要比较值需要用.equals....
    是这样么.
    CallFold
        5
    CallFold  
       2017-09-25 12:00:26 +08:00
    常量池
    lzx801
        6
    lzx801  
       2017-09-25 12:01:19 +08:00
    When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
    ZiLong
        7
    ZiLong  
    OP
       2017-09-25 12:01:37 +08:00
    @rozbo `java` 是被加载到 String 的字符串常量池了。但是 toString 不是返回一个新的 String 对象么?怎么会相等
    yinheli
        8
    yinheli  
       2017-09-25 12:18:24 +08:00   2
    推荐书籍: 《深入理解:java 虚拟机》

    intern 不同的虚拟机可能实现不同,HotSpot ( oracle jdk,openjdk )中不同的版本也有差别。
    你应该用的是 jdk 7 及以上版本。

    jdk7 开始,不再复制 string 实例到永久代,只是在常量池记录首次出现的实例引用,它返回的是首次创建实例的引用。

    java 这个字符串比较特殊,你没写但是其他的地方也用到过。它已经在常量池(引用)里了。
    adslxyz
        9
    adslxyz  
       2017-09-25 12:51:20 +08:00   4
    其实这段代码的结果在不同的虚拟机实现上可能是不同的。

    比如在 Oracle JDK8 中,是 true,false.

    而在 OpenJDK8 中,就是 true,true.

    具体原因可以参看 Oracle JDK8 的代码:

    路径:./jdk/src/share/classes/sun/misc/Version.java.template

    其中:

    ```
    private static final String launcher_name =
    "@@launcher_name@@";
    ```

    这个 @@launcher_name@@是模版占位符,会被替换为配置文件里指定的值。

    如果是 Oracle JDK8,LAUNCHER_NAME=java

    如果是 OpenJDK8 的话,LAUNCHER_NAME=openjdk

    所以 Oracle JDK8 在初始化 sun.misc.Version 类的时候会将"java"给 intern。

    同理,OpenJDK8 则会将"openjdk"给 intern。
    SuperMild
        10
    SuperMild  
       2017-09-25 13:23:56 +08:00
    google java string intern,前面几个连接就把这个问题说得不能更清楚了,基础技术问题为什么不 google 呢。
    ZiLong
        11
    ZiLong  
    OP
       2017-09-25 15:09:22 +08:00
    @lzx801 我其实在问之前反复看了这段话,然而我满脑子里反应的是字符串常量池是把它拷贝过去的。。。
    不过看了 @yinheli 的回答才知道原来 JDK6 还真这么做的
    ZiLong
        12
    ZiLong  
    OP
       2017-09-25 15:09:56 +08:00
    @yinheli
    @adslxyz
    感谢两位!
    ZiLong
        13
    ZiLong  
    OP
       2017-09-25 15:11:06 +08:00
    @adslxyz 请问大神是怎么在这么多类里找到`java`这个字符串是出现在哪个类呢
    shard
        14
    shard  
       2017-09-25 16:49:33 +08:00
    @ZiLong #13
    我来教你一个方法:
    dump 你的堆;
    下载 Eclipse Memory Analyzer ;
    导入你 dump 文件;
    然后 oql 搜索 select * from java.lang.String s where s.toString() = "java",在结果中 list incoming object
    大概这样。
    hubert3
        15
    hubert3  
       2017-09-25 16:55:19 +08:00
    @yinheli 是不是不太准确?java7 的常量池也在永久代里面,java8 开始才没有永久代
    ZiLong
        16
    ZiLong  
    OP
       2017-09-25 23:12:58 +08:00
    @hubert3 虽然永久代是 Java8 移除的,但是在 Java 7 中,常量池就被移出了永久代,参见官方说明: [http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html]( http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html)
    ```
    Area: HotSpot
    Synopsis: In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.
    RFE: 6962931
    ```
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3178 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 12:18 PVG 20:18 LAX 05:18 JFK 08:18
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86