详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt399

我看到一个问题 https://segmentfault.com/q/10... 是关于 String.intern() 的, 感觉比较有意思, 于是自己也去探索了一下, 有了一些自己的见解, 于是在此记录下来.

我们首先来看一个例子:

// 1
String str1 = new StringBuilder("ja").append("va").toString();
System.out.println(str1.intern() == str1);
// 2
String str2 = new StringBuffer("编").append("程").toString();
System.out.println(str2.intern() == str2);
// 3
String str3 = new StringBuffer("编").append("程").toString();
System.out.println(str3.intern() == str3);

这个例子会输出什么呢? 有些读者朋友可能没有想到, 其实上面的例子在不同的 JDK 版本中运行, 会有不同的结果的. 那么接下来我们来试一下吧:

// 使用 JDK6 进行编译运行:false, false, false
// 使用 JDK7 进行编译运行:false, true, false

为什么结果会不同呢?首先我们来看一下第一部分:

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

这里 JDK6 和 JDK7 都是打印的 false, 其原因是 "java" 字符串常量比较特殊, 它是固定存在字符串常量池中的, 因此 "str1.intern()" 返回的就是字符串常量池中的对象的引用, 和堆上的 str1 就自然是不相等了.

接下来我们来分析一下第二部分的代码:

// 2
String str2 = new StringBuffer("编").append("程").toString();
System.out.println(str2.intern() == str2);

在这里 JDK6 和 JDK7 的输出有了差异, 其具体原因是 JDK6 和 JDK7 对 String.intern() 方法的实现的不同.在 JDK6 及以前的 JDK 中:

intern() 方法会把首次遇到的字符串实例 **复制** 到永久代中, 然后返回永久代中的实例.

而对于 JDK7 以及之上的JDK:

当遇到第一次出现的字符串时, intern() **不再复制实例**, 而是在常量池中记录首次出现的实例的引用, 并且 intern() 返回的是此实例引用.

根据 JDK6 和 JDK7 的 intern() 方法的区别, 我们就知道了在第二部分的代码中, "编程" 这个字符串是第一次出现的, 因此在 JDK6 中, 会将此对象的实例拷贝一份然后存放到常量池中, intern() 返回的是在常量池中拷贝后的新对象的引用, 进而就和堆上的 str1 不等了; 而在 JDK7 中, 由于 intern() 方法的实现不同, 这个方法并不会拷贝一份对象实例到常量池中, 而是在常量池中记录此对象的引用, 因此 intern() 返回的引用其实和堆中的 str1 是一样的.

有了前面的认知, 我们对第三部分的代码的输出结果就比较熟悉了:

// 3
String str3 = new StringBuffer("编").append("程").toString();
System.out.println(str3.intern() == str3);

第三部分代码和第二部分代码其实是一样的, "编程" 这个字符串已经在第二部分的代码中出现了, 因此在常量池中已经存在了, 因此 str3.intern() 返回的是常量池中的对象的引用, 和堆上的 str3 自然是不一样的, 因此不论在 JDK6 还是 JDK7 中, 输出的都是 false.

关于 String.intern() 的思考的更多相关文章

  1. C#的字符串优化-String.Intern、IsInterned

    https://www.jianshu.com/p/af6eb8d3d4bf 首先看一段程序: using System; class Program { static void Main(strin ...

  2. Java提高篇——理解String 及 String.intern() 在实际中的应用

    1. 首先String不属于8种基本数据类型,String是一个对象.   因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ...

  3. 深入理解Java String#intern() 内存模型

    原文出处: codelog.me 大家知道,Java中string.intern()方法调用会先去字符串常量池中查找相应的字符串,如果字符串不存在,就会在字符串常量池中创建该字符串然后再返回. 字符串 ...

  4. 常量池之String.intern()方法

    JDK7将String常量池从Perm区移动到了Java Heap区.在JDK1.6中,intern方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中的实例.但是在JDK1.7以后,Str ...

  5. String放入运行时常量池的时机与String.intern()方法解惑

    运行时常量池概述 Java运行时常量池中主要存放两大类常量:字面量和符号引用.字面量比较接近于Java语言层面的常量概念,如文本字符串.声明为final的常量值等. 而符号引用则属于编译原理方面的概念 ...

  6. 字符串常量池和String.intern()方法在jdk1.6、1.7、1.8中的变化

    字符串常量池也是运行时常量池 jdk1.6中,它是在方法区中,属于“永久代” jdk1.7中,它被移除方法区,放在java堆中 jdk1.8中,取消了“永久代”,将常量池放在元空间,与堆独立了 pub ...

  7. string.intern

    在翻<深入理解Java虚拟机>的书时,又看到了2-7的 String.intern()返回引用的测试. 总结一句话: jdk1.7之前,调用intern()方法会判断常量池是否有该字符串, ...

  8. 运行时常量池中的符号引用/String.intern() /ldc指令

    运行时常量池,之前放在方法区(永久代)中,1.8之后被转移到元空间,放到了native memory中. 具体的数据结构是:(看对象的内存布局,句柄访问还是对象头中保存指向类的元数据的指针,这里以对象 ...

  9. synchronized (string.intern())

    在jdk7下慎用String.intern()作为synchronized的对象锁: https://www.cnblogs.com/yhlx/p/3498387.html String.intern ...

随机推荐

  1. [补档]happiness

    happiness 题目 传送门:http://cogs.pro/cogs/problem/problem.php?pid=1873 高一一班的座位表是个n×m的矩阵,经过一个学期的相处,每个同学和前 ...

  2. hdu 6047 Maximum Sequence(贪心)

    Description Steph is extremely obsessed with "sequence problems" that are usually seen on ...

  3. HDU5744 Keep On Movin (思维题,水题)

    Problem Description Professor Zhang has kinds of characters and the quantity of the i-th character i ...

  4. python--DenyHttp项目(2)--ACM监考客户端1.0版

    修复了: 360搜索可以使用的漏洞 更新版本,上一版本复制的Hosts文件保留的漏洞 #coding:gbk import os import sys from subprocess import * ...

  5. Java Socket 编程

    1. 背景 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节.你可以直接使用这些类和 ...

  6. 安徽省2016“京胜杯”程序设计大赛_H_单身晚会

    单身晚会 Time Limit: 1000 MS Memory Limit: 65536 KB Total Submissions: 53 Accepted: 16 Description ​ZJ和Z ...

  7. Centos 7.3 安装mysql5.7.19 各种调试就不多说了

    mysql 5.7.19linux-glibc2.12 (x86_64) 安装 1.在安装目录进行解压2.mv解压目录为mysql3.创建mysql的用户 useradd -s /sbin/nolon ...

  8. JavaScript中的EcMAScript学习笔记

    一.Javascript概述(知道)    a.一种基于对象和事件驱动的脚本语言    b.作用: 给页面添加动态效果    c.历史: 原名叫做livescript.W3c组织开发的标准叫ECMAs ...

  9. TestNG的组测试和组中组测试

    在编写测试的过程中,我们经常遇到只想执行个别或者某一部分/某一类型的测试用例,这时我们可以使用TestNG的分组测试方法 分组测试在配置时,TestNG执行的原则是:只保留最小集合进行执行 看代码: ...

  10. KMS注册

    --KMS注册 -------------2014/03/25 --Read this First http://social.technet.microsoft.com/wiki/contents/ ...