字符串常量池与intern方法

看了几篇关于intern方法的文章,总结如下:

一、主要知识点:

1、使用引号声明的字符串常量都会直接在字符串常量池中生成

2、intern方法在jdk1.6与jdk1.7中有点区别,主要原因是jdk1.7中将常量池移到了堆中

3、使用intern方法会很大程度的节省内存


二、Java中字符串创建的两种方式:

Java中字符串对象创建有两种形式,

一种为字面量形式,如String str=" hello",

另一种就是使用标准的构造对象的方法,如String str=new String("hello");

这两种经常使用,在内存上面有一些区别。这一切都是JVM为了减少字符串对象重复创建,其维护了一个特殊的内存,这段内存就是字符串常量池


工作原理

当代码中出现字面量形式创建字符串对象时吗,JVM就会首先对这个字面量进行检查,,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象就被创建,然后将这个引用放入字符串常量池中,并返回该引用。

String str1="hello"

JVM检测这个字面量,这里我们认为没有内容为"hello"的对象存在。JVM通过字符串常量池查找不到内容为"hello"的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量str1。


String str2="hello"

同样JVM还是要检测这个字面量,JVM通过查找字符串常量池,发现内容为”droid”字符串对象存在,于是将已经存在的字符串对象的引用返回给变量str2。注意这里不会重新创建新的字符串对象。

验证是否为str1和str2是否指向同一对象,我们可以通过这段代码

System.out.println(str1 == str2);

结果为true。


String str3 = new String("hello");

当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。因此我们使用下面代码测试一下,

String str3 = new String("hello");
System.out.println(str1 == str3);

结果如我们所想,为false,表明这两个变量指向的为不同的对象。


三、JDK1.6与JDK1.7中intern方法的区别:

1、JDK1.6中

在JDK1.6中,常量池是放在Perm区(属于方法区)中的,这是和堆区完全分开的。

在JDK1.6中,intern()方法的作用:

检查字符串池里是否存在"hello"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会把"hello"添加到字符串池中,然后再返回它的引用。

(1)

	public static void main(String[] args) {
		//在常量池中添加字符串hello
		String s1="hello";
		//由于常量池中已经存在"hello",所以返回该字符串
		String s2=s1.intern();
		System.out.println(s2);       //hello
		//s1和s2都指向常量池中"hello"
		System.out.println(s2==s1);   //true
	}


(2)
	public static void main(String[] args) {
		//在堆中创建字符串并且在常量池中添加字符串hello  因为使用引号声明的字符串常量都会直接在字符串常量池中生成
		String s1=new String("hello");
		//由于常量池中已经存在"hello",所以返回该字符串
		String s2=s1.intern();
		System.out.println(s2);       //hello
		//由于s1指向的字符串在堆中,而s2指向的字符串在常量池中,所以地址不同(==判断的是地址)
		System.out.println(s2==s1);   //false
	}

(3)

	public static void main(String[] args) {
		//在堆中创建字符串"hello world"  在常量池中分别创建"hello"与"world"
		String s1=new String("hello")+new String("World");
		//由于常量池中不存在"hello world",所以添加该字符串,并返回引用
		String s2=s1.intern();
		System.out.println(s2);       //helloWorld
		//由于s1指向的字符串在堆中,而s2指向的字符串在常量池中,所以地址不同(==判断的是地址)
		System.out.println(s2==s1);   //false
	}

注意:在jdk1.7中会输出true,下面将介绍。


2、在JDK1.7中

在JDK1.7中,将常量池放到了堆中。

正常情况下,使用new创建的字符串对象的引用不会放入字符串常量池,但是在使用JDK1.7的情况下,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。


	public static void main(String[] args) {
		//在堆中创建字符串"hello world"  在常量池中分别创建"hello"与"world"
		String s1=new String("hello")+new String("World");
		/*
		 * 由于常量池中不存在"hello world",但是在堆中有该字符串,
		 * 所以将引用s1返回,即s2也指向堆中的字符串
		 */
		String s2=s1.intern();
		System.out.println(s2);       //helloWorld
		//所以地址相同
		System.out.println(s2==s1);   //true
		
		String s3="helloWorld";
		//常量池中已经存在"helloWorld"的引用,所以s3也直接指向堆中的字符串
		System.out.println(s3==s1);  //true
	}


关于intern()方法为什么能够节省内存,参见 Java技术——你真的了解String类的intern()方法吗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值