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

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

  •  
  •   ZiLong · 2017-09-25 11:27:34 +08:00 · 4099 次点击
    这是一个创建于 2646 天前的主题,其中的信息可能已经有所发展或是发生改变。
            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   ·   实用小工具   ·   5590 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:18 · PVG 11:18 · LAX 19:18 · JFK 22:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.