不同 JDK 的 String.Intern ( ) 的不同之处

最近在读 《深入理解java虚拟机》,总结一下 String.intern 知识点,引入书中的一个题目:

    public class RuntimeConstantPoolOOM {
            public static void main(String[] args){
                String str1 = new StringBuilder("计算机").append("软件").toString();
                System.out.println(str1.intern() == str1);

                String str2 = new StringBuilder("ja").append("va").toString();
                System.out.println(str2.intern() == str2);

              }

        }

这段代码在JDK 1.6中运行,会得到两个false,而在JDK1.7中运行,会得到一个true和一个false。产生差异的原因是:在JDK1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而StringBuildler创建的字符串实例在Java堆上,所以必然不是一个引用,将返回false。而JDK1.7中(以及部分其他虚拟机,例如JRockit)的intern()实现不会再 复制实例,只是在常量池中记录首次出现实例的引用,因此intern()返回的引用和由StringBuilder创建的字符串实例是同一个;对str2比较返回false是因为“java”这个字符串在执行StringBuilder.toString()之前已经出现过,字符串常量池中已经有它的引用,不符合首次出现的规则,而"计算机软件"这个字符串则是首次出现的,因为返回true;

下面引入几幅图对 intern 方法作如下总结:
  • new String 都是在堆上创建字符串对象。当调用 intern() 方法时,JDK1.6中编译器会将字符串添加到常量池中,并返回指向该常量的引用。
image
image
  • 通过字面量赋值创建字符串(如:String str=”twm”)时,会先在常量池中查找是否存在相同的字符串,若存在,则将栈中的引用直接指向该字符串;若不存在,则在常量池中生成一个字符串,再将栈中的引用指向该字符串。
image
  • 常量字符串的“+”操作,编译阶段直接会合成为一个字符串。如string str=”JA”+”VA”,在编译阶段会直接合并成语句String str=”JAVA”,于是会去常量池中查找是否存在”JAVA”,从而进行创建或引用。
  • 对于final字段,编译期直接进行了常量替换(而对于非final字段则是在运行期进行赋值处理的)。
    final String str1 = ”ja” ;

    final String str2 = ”va” ;

    String str3 = str1+str2 ;

在编译时,直接替换成了 String str3 = ”ja” + ”va”,根据第三条规则,再次替换成 String str3=”JAVA” 。

  • 常量字符串和变量拼接时(如:String str3 = baseStr + “01” ;)会调用 stringBuilder.append() 在堆上创建新的对象。
  • JDK 1.7 后,intern 方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。简单的说,就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。

另外参考 关于String.intern()和new StringBuilder("").append("").toString();

先运行这个代码 ①

    String str3 = new StringBuilder("ni").append("hao").toString();

    System.out.println(str3==str3.intern());

通过上面的解释,运行结果为true.

在运行这个代码 ②

    String str3 = new StringBuilder("nihao").toString();

    System.out.println(str3==str3.intern());

其结果是什么 ? 应该还是 true 吧 ,毕竟通过上一个运行结果可以知道 "nihao" 这个字符串常量没有被预先加载到常量池中 。
但是运行结果却是 false .

解释如下 :上面的 ① 代码等价于下面的代码

    String a = "ni";

    String b = "hao";
    
    String str3 = new StringBuilder(a).append(b).toString();
    
    System.out.println(str3==str3.intern());

很容易分析出 :

“nihao” 最先创建在堆中 str3.intern() 然后缓存在字符串常连池中 运行结果为 true .

代码 ② 等价于

    String a = "nihao";

    String str3 = new StringBuilder(a).toString();
    
    System.out.println(str3==str3.intern());

很容易分析出:

“nihao” 最先创建在常量池中, 运行结果为false.

new String()和new StringBuilder()同样的原理,由此对于一道 经典的Java面试题

在Java中,new String("hello")这样的创建方式,到底创建了几个String对象 ?

题目下答案众说纷纭,有说1的有说2的,我觉得各有各的道理,如果常量池中有“hello”的字符串,当然只会创建1个,如果没有则会创建2个;

new String ("hello")相当于如下代码:

    String temp = "hello";  // 在常量池中

    String str = new String(temp); // 在堆上
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350