java String类的intern()方法
来源:互联网 发布:c语言经典案例 编辑:程序博客网 时间:2024/05/18 13:31
《深入理解java虚拟机》今天看到了2.2.6运行时常量池(当然其实之前寒假看过了,但是好久不看遗忘了,所以又从头开始看起...),谈到了String类的intern()方法,因为不是太了解,所以查了一下资料,运行了一下代码,学习了一下。参考资料网址:http://www.importnew.com/21024.html#comments
1、字符串两种赋值方式及区别:
1.1、通过字面量赋值
String str="str";
String str=new String("str");
1.3、二者在jvm中的区别
首先,应该明确,运行时常量池中仅仅存放2类内容:a各种字面量;b符号引用。
通过字面量赋值创建字符串时,会优先在常量池中查找是否已经存在相同的字符串,倘若已经存在,栈中的引用直接指向该字符串的引用;倘若不存在,则在常量池中生成一个该字符串,再将栈中的引用指向该字符串引用。
而通过new的方式创建字符串时,就直接在堆中生成一个字符串的对象(备注,JDK 7 以后,HotSpot 已将常量池从永久代转移到了堆中。所有此时调用String.intern()方法时,不会再复制实例,只是在常量池中记录首次出现的实例引用详细信息可参考《JDK8内存模型-消失的PermGen》一文),栈中的引用指向该对象。对于堆中的字符串对象,可以通过 intern() 方法来将字符串添加到常量池中,并返回指向该常量的引用。由StringBuilder创建的字符串在java堆上。
2、代码示例:
public class TempTest { public static void main(String[] args) { //test1 String str11="abc"; String str12=new String("abc"); String str13=str12.intern(); System.out.println(str11==str12);//false System.out.println(str11==str13);//true //test2 String baseStr="baseStr"; final String baseFinalStr="baseStr"; String str21="baseStr01"; String str22="baseStr"+"01"; String str23=baseStr+"01"; String str24=baseFinalStr+"01"; String str25=new String("baseStr01").intern(); System.out.println(str21==str22);//true System.out.println(str21==str23);//false System.out.println(str21==str24);//true System.out.println(str21==str25);//true //test3 String str31=new String("str")+new String("01"); str31.intern(); String str32="str01"; System.out.println(str31==str32);//true //test4 String str41="str01"; String str42=new String("str")+new String("01"); str42.intern(); System.out.println(str41==str42);//false }}
代码结果分析:
2.1、test1
str11:为字面量赋值,故为存放在常量池中。
str12:为new生成的对象值,故存放在堆中。
str13:str12通过intern方法将str12引用添加到常量池中,由于str12="abc",而常量池中已经有abc,所以在添加到常量池的过程中直接返回:常量池中abc的引用。故str11==str13。
所以打印结果为:true,false。
2.2、test2
str21:为字面量赋值,故为存放在常量池中。
str22:jdk1.6后,常量字符串的+操作,在编译期间直接合并为一个字符串。故也为字面量赋值,所以str22得到的是和str21相同的引用。
str23:实质是stringBuilder.append()生成的结果,故与str21不是同一引用。
str24:因为包含final字段,故在编译期间进行了常量替换,所以str24直接获得了常量池str21的引用。
str25:由intern()方法可知,str21和str25是一样的引用。
所以打印结果为:true,false,true,true。
2.3、test3
str31:new生成的String对象,所以指向堆中的引用。
str32:因为str32在进行字面量赋值前,因为intern()方法的调用,导致常量池中生成了一个值为“abc”,指向堆中的引用。
原理:JDK 1.7后,对于第一种情况返回true,但是调换了一下位置返回的结果就变成了false。这个原因主要是从JDK 1.7后,HotSpot 将常量池从永久代移到了元空间,正因为如此,JDK 1.7 后的intern方法在实现上发生了比较大的改变,JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。
所以打印结果为:true。
2.4、test4
str41:为常量池中引用
str42:为堆中引用
所以打印结果为:false
3、常见面试问题:
有了对以上的知识的了解,我们现在再来看常见的面试或笔试题就很简单了:
Q:String s = new String(“xyz”),创建了几个String Object?
A:两个,常量池中的”xyz”和堆中对象。
Q:下列程序的输出结果:
String s1 = “abc”;
String s2 = “abc”;
System.out.println(s1 == s2);
A:true,均指向常量池中对象。
Q:下列程序的输出结果:
String s1 = new String(“abc”);
String s2 = new String(“abc”);
System.out.println(s1 == s2);
A:false,两个引用指向堆中的不同对象。
Q:下列程序的输出结果:
String s1 = “abc”;
String s2 = “a”;
String s3 = “bc”;
String s4 = s2 + s3;
System.out.println(s1 == s4);
A:false,因为s2+s3实际上是使用StringBuilder.append来完成,会生成不同的对象。
Q:下列程序的输出结果:
String s1 = “abc”;
final String s2 = “a”;
final String s3 = “bc”;
String s4 = s2 + s3;
System.out.println(s1 == s4);
A:true,因为final变量在编译后会直接替换成对应的值,所以实际上等于s4=”a”+”bc”,而这种情况下,编译器会直接合并为s4=”abc”,所以最终s1==s4。
Q:下列程序的输出结果:
String s = new String(“abc”);
String s1 = “abc”;
String s2 = new String(“abc”);
System.out.println(s == s1.intern());
System.out.println(s == s2.intern());
System.out.println(s1 == s2.intern());
A:false,false,true,具体原因参考第二部分内容。
- Java的String类中的intern()方法
- Java String类的intern方法
- java---String类的intern方法
- java String类的intern()方法
- Java -- String的intern方法
- (Java)String的intern方法
- Java String类--intern方法
- java-String类intern()方法
- String 类的intern方法
- java String.intern() 方法
- Java String.intern()方法
- JAVA中String类的intern()方法的作用
- JAVA中String类的intern()方法的作用
- JAVA中String类的intern()方法的作用
- JAVA中String类的intern()方法的作用
- JAVA中String类的intern()方法的作用
- JAVA中String类的intern()方法的作用
- JAVA中String类的intern()方法的作用
- 剑指offer-从上往下打印二叉树
- 常见的web攻击技术
- 民意调研工具的实现
- Html+Css学习第一天
- 前端HTML5几种存储方式的总结
- java String类的intern()方法
- 微机原理实验二之8259A中断控制器
- 2017年高考理数12题压轴选择题的暴力计算
- 排序算法之堆排序
- 2017年6月7日
- 多机多broker
- .html(),.text()和.val()的差异总结
- 指针作为函数参数(处理数组的四种方式)
- ssh框架xml配置文件集合