常量池、运行时常量池、字符串常量池

  • 常量池、运行时常量池、字符串常量池
  • intern()方法变化
  • 实例解析

一.常量池、运行时常量池、字符串常量池
1.常量池(即类文件常量池)
常量池是当class字节码文件被Java虚拟机加载后存放在方法区各种字面量(Literal)和符号引用

java源码编译成class字节码文件, class字节码文件记录了当前这个类的所有相关信息,
其中有一个很重要的部分被称为常量池
常量池存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)

字面量包含文本字符串、八种基本类型的值、声明final的常量等
符号引用包含类和接口的全限定名、字段的名称和描述符、方法的名称和描述符

2.运行时常量池
运行时常量池是当class字节码文件被加载到内存后, Java虚拟机会将class字节码文件中常量池里的内容转移到运行时常量池里

相较于类文件常量池, 运行时常量池更有动态性. Java语言并不要求常量一定只有编译期才能产生,
即并非预置入Class文件中常量池的内容才能进入方法区运行时常量池, 运行期间也可能将新的常量放入池中, 如String类的intern()方法
jdk6及以下版本, 运行时常量池包含字符串常量池, 存放于方法区中(永久代实现)
jdk7, 将字符串常量池移到堆中, 运行时常量池位于方法区中(永久代实现)
jdk8, HotSpot VM移除了永久代, 使用本地内存中的元空间实现方法区, 字符串常量池在堆中, 运行时常量池位于方法区中(元空间实现)

java中的基本类型的包装类基本都实现了常量池技术
即Byte, Short, Integer, Long, Character, Boolean
这5种包装类默认创建了数值[-128, 127]的相应类型的缓存数据

Integer a = 10;
Integer b = 10;
System.out.println(a == b); // true

Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false, 200 > 127

Integer a = 10; Java在编译时会直接将代码封装成Integer a = Integer.valueOf(10);
从而使用常量池中的对象
注意: Float和Double并没有对应的常量池

3.字符串常量池(全局字符串池)
常量池(类文件常量池)的文本字符串字面量会在类加载时进入字符串常量池

字符串常量池, 即为了避免多次创建字符串对象, 而将字符串在jvm中开辟一块空间,
储存不重复的字符串

直接使用双引号""声明字符串(字面量创建), 如String str1 = “aaa”;
JVM会去字符串常量池查找是否存在相同的字符串, 如果不存在, 会在字符串常量池中创建一个对象, 然后返回这个对象的引用地址. 如果存在, 则不创建对象, 返回字符串常量池的这个对象地址

使用new关键字创建, 如String a = new String(“aaa”);
JVM会去字符串常量池查找是否存在相同的字符串, 如果不存在, 首先在字符串常量池中创建一个对象, 然后在堆中创建一个对象, 返回堆中对象地址. 如果存在则无需在字符串常量池中创建对象, 直接在堆中创建一个对象, 返回堆中对象地址

二.intern()方法变化
JDK6及之前:
当一个String对象调用intern()方法时, 如果字符串常量池已包含该对象对应的字符串,
则返回字符串常量池中字符串的引用
否则拷贝该对象到字符串常量池中并返回字符串常量池中对象的引用

JDK7及之后:
当一个String对象调用intern()方法时, 如果字符串常量池已包含该对象对应的字符串,
则返回字符串常量池中字符串的引用
否则将该对象在堆中的引用放入字符串常量池中并返回该引用

三.实例解析

// 字符串常量池创建对象abc, 堆中创建对象abc, str1指向堆对象abc
String str1 = new String("abc");
// 字符串常量池存在对象abc, 返回字符串常量池对象引用
str1.intern();
// 字符串常量池存在对象abc, str2指向字符串常量池对象
String str2 = "abc";
System.out.println(str1 == str2); // false
// 字符串常量池创建对象abc, 堆中创建对象abc, str1指向堆中对象abc
String str1 = new String("abc");
// 字符串常量池存在对象abc, str2指向字符串常量池对象abc
String str2 = "abc";
// 字符串常量池存在对象abc, 返回字符串常量池对象abc
str1.intern();
System.out.println(str1 == str2); // false
// 字符串常量池创建对象abc和def, 堆中创建对象abc、def、abcdef, str1指向堆对象abcdef
String str1 = new String("abc") + new String("def");
// 字符串常量池不存在对象abcdef, 返回堆对象abcdef引用
str1.intern();
// 字符串常量池有堆对象abcdef引用
String str2 = "abcdef";
System.out.println(str1 == str2); // true
// 字符串常量池创建对象abc和def, 堆中创建对象abc、def、abcdef, str1指向堆对象abcdef
String str1 = new String("abc") + new String("def");
// 字符串常量池创建对象abcdef, str2指向字符串常量池对象abcdef
String str2 = "abcdef";
// 字符串常量池存在对象abcdef, 返回字符串常量池对象abcdef
str1.intern();
System.out.println(str1 == str2); // false
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值