String.intern()

String.intern()

最近看java内存模型,提到String的intern()方法,发现还蛮纠结的,所以稍微整理一下。

一、String在内存中的位置

Class Test {
....
String str = “hello";
....
}

String的常用方式如上,"hello"这种形式称为字面量。编译生成class文件时,字面量存在class文件的常量池中。运行程序要用到Test类时,Test.class文件内容会被加载到内存的方法区中。class中常量池的大部分内容会被加载到运行时常量池,但String不是。“hello”的引用会创建在字符串常量池中,而“hello”对象创建中堆中,如下图所示。

每个线程独享的空间包括程序计数器、本地方法栈、虚拟机栈。程序计数器用于线程切换时标记代码执行的位置。本地方法栈,用于执行非java的方法,如c/c++的方法等。虚拟机栈,就是执行用于java方法了,每一个java方法对应一个栈帧。 字面量


“hello”对象创建后,String str对象还没有创建。主线程执行到String str = “hello"时,首先用equals方法判断字符串常量池中是否已经存在“hello”对象的引用,如果已存在,就将str指向该对象,如下图所示。如果不存在,就在堆中创建,并在字符串常量池中存放其引用,然后将引用赋值给str。如下图所示。 字面量


Class Test {
....
String str = “hello";
String str1 = “hello";
String str2 = “hello";
....
}

如果像这样创建多个”hello“,都不会申请新的内存,如下图: 字面量


接下来是new String创建方式:

Class Test1 {
....
String str = new String("hello");
String str1 = “hello";
....
}

用new创建String时,总是会申请一块新内存,不考虑常量池中是否已存在。如上代码,加载Test1时,首先用字面量”hello“创建对象,并将引用放入到字符串常量池。之后创建str时,会再申请一块内存,新建另一个”hello“,并将引用赋值给str。如下图所示。创建str1时,去字符串常量池中查找,找到已存在的上面一个”hello“,所以不需要申请新内存,直接将其引用赋值给str1. newString.png


二、intern基本介绍

String类维护自己的字符串常量池,它是全局共享的。调用String.intern方法时,判断字符串在常量池中是否存在(根据equals方法判断),如果存在,就返回常量池中对应字符串的引用;如果不存在,就将此字符串的值加入到常量池中,并返回此字符串的引用。

注意,字符串常量池存放的是对象的引用,不是对象本身,java的对象创建都在堆中。

intern的作用是什么呢?

intern()的作用是,String b=a.intern();则直接将b指向了字符串常量池中已有的一个字符串,不需要新开辟一块内存,节省空间。但字符串常量池的大小是有限的,如果太多,也会影响效率。

三、jdk7下intern示例

四、jdk6/jdk7中intern

前面图示中,internedString都位于永久代中的字符串常量池中,这是jdk6下的情况。而在jdk7中,internedString被挪到了heap区,且内部实现也有所变化。

jdk6中,intern()将首次出现的字符串复制到字符串常量池,并返回引用。 jdk7中,intern()不再复制实例,只在常量池中记录首次出现的实例引用,并返回该引用。


问题:jdk7中,字符串常量池在Heap中布局是怎样的呢?不会被垃圾回收吗?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值