常量池之字符串常量池String.intern()
运行时常量池是方法区(PermGen)的一部分。
需要提前了解:
1. JVM内存模型。
2. JAVA对象在JVM中内存分配
常量池的好处
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
- Java的自动装箱中其实就使用到了运行时常量池。详见:Java 自动装箱与拆箱的实现原理
- 还有字符串常量池。
字符串进入到常量池的两种方法:
1. new String()的实例调用intern()方法。
执行intern()方法时,若常量池中不存在等值的字符串,JVM就会在常量池中 创建一个等值的字符串,然后返回该字符串的引用。
2. “”(引号)引起来的内容(字面量)。
引号引起来的字符串,首先从常量池中查找是否存在此字符串,如果不存在则在常量池中添加此字符串对象,然后引用此字符串对象。如果存在,则直接引用此字符串。
重要提示:虚拟机启动时常量池中就存在“java”字符串实例,下面代码中s2调用intern()方法时,只是返回常量池中“java”实例的引用,而没有添加“java”实例。
先看下,下面的代码
public class Test {
public static void main(String[] args) {
String s1 = new StringBuilder().append("aa").append("bb").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder().append("ja").append("va").toString();
System.out.println(s2.intern() == s2);
}
}
输出结果如下:
JDK6
false
false
JDK7、JDK8
true
false
为什么不同版本的JDK输出的结果还不一样呢?带着疑问我们分别分析下JDK1.6 和JDK1.7-JDK1.8的常量池内存模型。
JDK1.6 常量池内存模型

如图中,我们可以看到常量池位于方法区(PermGen),常量池中引用的字符串实例也在常量池中。
1、通过调用intern()方法,会在常量池中生成一个相同字符串的对象
2、“”内的字符串都会添加到常量池中,相当于引用的方法区中的字符串对象。
根据上图内存模型然后我们在分析下代码:
String s1 = new StringBuilder().append(“aa”).append(“bb”).toString();
System.out.println(s1.intern() == s1);
s1生成的对象在堆中,而s1.intern()的对象在常量池中,所以返回false。
String s2 = new StringBuilder().append(“ja”).append(“va”).toString();
System.out.println(s2.intern() == s2);
s2生成的对象在堆中,而s2.intern()的对象也肯定在常量池中,所以也返回false。
JDK1.7-JDK1.8常量池内存模型

如图中,我们可以看到常量池位于方法区(PermGen),但常量池引用的字符串实例在堆中。(区别在这)
1. 通过调用intern()方法,会在常量池添加一个此字符串实例的引用,(前提:常量池中没有相同内容的字符串)。
2. “”内的字符串实例引用会添加到常量池中(前提:常量池中没有相同内容的字符串),如果常量池中存在,则引用常量池中的对象(防止重复创建对象)。
根据上图内存模型然后我们在分析下代码:
String s1 = new StringBuilder().append(“aa”).append(“bb”).toString();
System.out.println(s1.intern() == s1);
s1生成的对象在堆中,此时常量池中没有跟s1内容相同的字符串,所以在调用intern方法时,会在常量池中添加此对象的引用,所以返回为true。
String s2 = new StringBuilder().append(“ja”).append(“va”).toString();
System.out.println(s2.intern() == s2);
s2生成的对象在堆中,而此时常量池中已经有一个跟s2内容相同的字符串常量,当s2调用intern方法时,返回常量池中已经存在的实例(相当于堆中有两个相同内容的实例:一个是new 出来的,一个是常量池中的)所以返回的结果为false。
常量池之字符串常量池String.intern()的更多相关文章
- JVM 常量池、运行时常量池、字符串常量池
常量池: 即class文件常量池,是class文件的一部分,用于保存编译时确定的数据. 保存的内容如下图: D:\java\test\out\production\test>javap -ver ...
- Class常量池、运行时常量池、字符串常量池的一些思考
Class常量池.运行时常量池.字符串常量池 class常量池 java代码经过编译之后都成了xxx.class文件,这是java引以为傲的可移植性的基石.class文件中,在CAFEBABE.主次版 ...
- 彻底搞清楚class常量池、运行时常量池、字符串常量池
彻底搞清楚class常量池.运行时常量池.字符串常量池 常量池-静态常量池 也叫 class文件常量池,主要存放编译期生成的各种字面量(Literal)和符号引用(Symbolic Reference ...
- 运行时常量池中的符号引用/String.intern() /ldc指令
运行时常量池,之前放在方法区(永久代)中,1.8之后被转移到元空间,放到了native memory中. 具体的数据结构是:(看对象的内存布局,句柄访问还是对象头中保存指向类的元数据的指针,这里以对象 ...
- String放入运行时常量池的时机与String.intern()方法解惑
运行时常量池概述 Java运行时常量池中主要存放两大类常量:字面量和符号引用.字面量比较接近于Java语言层面的常量概念,如文本字符串.声明为final的常量值等. 而符号引用则属于编译原理方面的概念 ...
- String:字符串常量池
String:字符串常量池 作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池: 字 ...
- Java String:字符串常量池(转)
作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么? 字符串常量池的设计思想是什么? 字符串常量池在哪里? 如何操作字符串常量 ...
- 从HotSpot VM源码看字符串常量池(StringTable)和intern()方法
引言 字符串常量池(StringTable)是JVM中一个重要的结构,它有助于避免重复创建相同内容的String对象.那么StringTable是怎么实现的?"把字符串加入到字符串常量池中& ...
- java字符串常量池——字符串==比较的一个误区
转自:https://blog.csdn.net/wxz980927155/article/details/81712342 起因 再一次js的json对象的比较中,发现相同内容的json对象使用 ...
随机推荐
- Codeforces Round #534 (Div. 2) Solution
A. Splitting into digits Solved. #include <bits/stdc++.h> using namespace std; int n; void sol ...
- Windows共享文件
通常局域网中处于同一工作组或同一域的计算机只要右键设置文件夹共享即可,但跨工作组或跨域的共享就需要设置一番了. 一.启用共享 二.关闭共享密码保护 这是英文版系统示例,中文版一样,就是在第一步向下拉一 ...
- confluence wiki 安装
1. 下载 wget https://www.atlassian.com/software/confluence/downloads/binary/atlassian-confluence-5.6.6 ...
- ThinkPHP5 快速入门文档
一. 5.0版本采用模块化的设计架构,默认的应用目录下面只有一个index模块目录,如果我要添加新的模块可以使用控制台命令来生成. 切换到命令行模式下,进入到应用根目录并执行如下指令: php thi ...
- CodeForces - 55D Beautiful numbers(数位DP+Hash)题解
题意:美丽数定义:一个正数能被所有位数整除.求给出一个范围,回答这个范围内的美丽数. 思路:一个数能被所有位数整除,换句话说就是一个数能整除所有位数的LCM,所以问题就转化为一个数能否被所有位数的LC ...
- 【eclipse】svn在线安装
Subclipse1.8 http://subclipse.tigris.org/update_1.8.x
- Mininet实验 测量路径损耗率
参照:基于Mininet测量路径的损耗率 在SDN环境中,可以利用控制器来测量特定路径的损耗率,在本实验中,基于Mininet脚本,设置特定的交换机间的路径损耗速率,然后编写POX脚本,实现对路径的损 ...
- 51Nod 1070 Bash游戏 V4(斐波那契博弈)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1070 题意: 思路: 这个是斐波那契博弈,http://blog.csd ...
- pairs 和 ipairs 的区别
ipairs 在迭代过程中是会直接跳过所有手动设定key值的变量.pairs不会跳过手动设置key值的变量. 实例 tab = {,,a="cd","d"} f ...
- 更改CentOS7登录画面的分辨率
设置成用VNC Viewer去连接虚拟机的CentOS7 , 可是分辨率都得等登录了才能生效. 登录画面显示时,分辨率老大了. 找到了下面的文章 , 把 home/<user>/.conf ...