[JVM] String#intern 面试必会
String#intern
本文主要通过一个小demo, 说明一下String#intern 的用法, 以及为什么会是这么个执行结果
`生活很苦, 时常我们会迷惘, 而我们要主动去寻找希望, 加油
`
从这个小程序说起
`文中小程序运行环境为 JDK 8
`
你确定你能说的清为什么是这个结果吗 ?
`注意看清题目, 谁和谁比较, 不要看错了, 别自以为是
`
`其实case2 case3 初看还是挺有迷惑性的 !
`
先说答案呢 ? 还是先讲源码呢 ? 纠结
尝试分析
String#intern 源码注释
先看下源码怎么说吧, 目的是看看这方法是干嘛的, `分析程序, 看源码准没错
`
大概翻译一下:
该方法用于返回字符串对象的规范表示。 由String类维护字符串池 ( 池刚开始为空池 ) 。
`
调用intern方法时,
``
如果池中已经包含与此String对象equals()方法相同的字符串,则返回池中的字符串引用。
``
否则,将此String对象添加到池中,并返回对此String对象的引用。
`因此,对于任何两个字符串s和t,当且仅当s.equals(t)为true时,s.intern()== t.intern()为true。
所有文字字符串和字符串值常量表达式均已插入。字符串文字是在Java™语言规范的3.10.5节中定义的。 返回值: 与该字符串具有相同内容的字符串,但保证来自唯一字符串池。
看了文档注释, 咱们大概了解了String#intern的作用,
从另一个角度, 看下 intern 单词的意思 ?
**`动词, 拘留
, 也能看出其实是想把字符串关押起来(
往常量池中添加对象
`)**
Case 解析
针对 case 挨个分析一波吧
case1
众所周知, `String origin1 = new String("张三"); 实际会产生两个字符串对象,
`
一个"张三"在字符串常量池中被引用, 另外一个在堆中被orgin1 引用,
因为池中已有"张三", origin1.intern() 返回的是常量池中的对象引用, 所以和 origin1 地址不相同
case2
String origin2 = new StringBuilder().append("aaa").append("bbb").toString();
这一步实际上会产生几个字符串对象呢?
常量池中会引用 "aaa" "bbb" 两个,
看下 StringBuilder#toString 源码, 实际上会返回一个 new String(value, 0, count);
String s1 = "aaabbb";
这一步 会往常量池中添加一个 "aaabbb" 对象
所以, origin2.intern() 返回的是 常量池中的地址, 和 origin2 地址不同
case3
case3 与 case2 只是少了 String s1 = "cccddd";
也就是说 常量池中不存在 "cccddd" 字符串, 那么 origin3.intern(), 执行结果会把字符串本身添加到常量池, 并返回自身引用, 所以这一步 origin3.intern() == origin3 是true
干货赠送: JVM背景知识
Hotspot VM , `JDK 7(包括) 以后
,
字符串常量池也就是 StringTable, 就从永久代移动到堆空间了
`, 跟普通对象其实没什么区别了, 也会参与GC 内存回收,
就是因为和普通对象属于同一空间了, 所以, 当池中字符串不存在时, 调用String#intern 才有可能返回他自身的引用, 复用了存储空间
而在 JDK 6 的情况下, StringTable 不属于堆空间, 所以不论什么时候调用String#intern方法都是另一个空间的对象, 和当前调用者内存地址肯定不同, 所以在JDK 6 的运行环境下, 咱们的 case3 打印结果会是 false !!!
课后习题
感兴趣的话, 可以在JDK 6 环境下运行看一下区别, 希望本文对你有帮助
版权声明: 本文为 InfoQ 作者【猴哥一一 cium】的原创文章。
原文链接:【http://xie.infoq.cn/article/b6598ee4456666d9f971b020b】。文章转载请联系作者。
评论