最近看了深入理解Java虚拟机,对String.intern()方法虚拟机的实现很是不理解,经过查找网上的各类文章,现在总结一部分。
在理解String.intern()方法之前,我觉得首先应该了解一下通过创建对象的方式和直接创建字符串的方式对象生成机制便于理解一下代码。
String str1 = new String("1");//--创建对象的方式
这种创建方式,是在堆中创建一个字符串为“1”的对象,并返回该字符串在堆中的地址信息,str1该引用指向堆中的地址信息。如图:
在JDK1.6中,String.intern()方法先去运行时常量池中查看有无该字符串,如果有,则直接返回该字符串在方法区的内存地址。如果没有则会先将该字符串保存在常量池中,并返回该字符串在方法区的内存地址。也就是在JDK1.6中无论是是否需要在产量中新建该字符串,都会返回在常量池中该字符串的引用,即是内存地址。
//----代码片段1(以下代码运行在JDK1.6的环境中)
String str1 = new String("1") + new String("2");//这一行代码中,在堆中产生了一个字符串为“12”的对象,但是在方法区中并没有“12”这个字符串,但需要注意的是,方法区中已经有了“1”和“2”的字符串。
String intern = str1.intern();//这一行代码中, str1.intern() 判断产量池中并没有“12”,于是在常量池中创建一个“12”的字符串,此时返回的是常量池中“12”这个字符串的地址信息。对于intern和str1来说,一个是在堆中的地址,一个是在常量池中的地址,所以,肯定是不相等的,所以intern == str1为false;
String str2 = "12";//这一行代码中,首先去常量池中查看有没有“12”,发现已经有了字符串“12”,这时候是字符串而不是引用,于是返回常量池中“12”这个字符串的地址信息,其实和intern是一样的返回值,所以intern==str2为true;同理,str1和str2,str1是堆中的地址信息,str2是常量池中的地址信息,所以str2==str1,也是false;
System.out.println(str1 == str2);//false
System.out.println(intern == str1);//false
System.out.println(intern == str2);//true
在JDK1.7中,String.intern()方法先去运行时常量池中查看有无该字符串,如果有,则直接返回该字符串在方法区的内存地址。这里与JDK1.6中是相同的。如果没有的话,则会将该字符串在堆中的内存地址复制一份,然后保存在方法区中,String.intern()方法返回的则是保存在方法区的内存地址信息,即该字符串对象在堆中的地址。
//----代码片段1(以下代码运行在JDK1.7的环境中)
String str1 = new String("1") + new String("2");//这一行代码中,在堆中产生了一个字符串为“12”的对象,但是在方法区中并没有“12”这个字符串,但需要注意的是,方法区中已经有了“1”和“2”的字符串。
String intern = str1.intern();//这一行代码中, str1.intern() 判断产量池中并没有“12”,于是将堆中“12”这个对象的地址信息复制到方法区中,并返回该地址信息(堆中的地址信息)。所以,intern的返回值与str1是一样的地址信息,intern == str1为true;
String str2 = "12";//这一行代码中,首先常产量池中查看有没有“12”,发现已经有了字符串“12”的引用,于是不再创建,直接返回该地址信息(堆中的地址信息)。所以,其实str2和str1是一样的地址信息,str1==str2为true;intern的返回值与str2也是一样的地址信息,所以intern == str2为true。
System.out.println(str1 == str2);//true
System.out.println(intern == str1);//true
System.out.println(intern == str2);//true
本文详细解析了Java中String.intern()方法在JDK1.6与JDK1.7的不同实现机制,对比了堆和方法区中字符串的创建与引用过程,通过具体代码演示了intern方法对字符串池的影响。

605

被折叠的 条评论
为什么被折叠?



