首先intern()方法的定义:当调用这个方法的时候,如果字符串常量池中有这个对象,就把常量池中的这个对象返回,没有就把当前对象加入到常量池并且返回当前对象的引用;
jdk1.6之前:将对象存入常量池;
jdk1.7: 将堆中引用存入常量池(字符串常量池位于堆中)
public static void main(String[] args) {
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
}
打印结果是
jdk6 下false false
jdk7 下false true
为什么jdk7下s3 ==s4呢不是两个完全不同的对象嘛
String s3 = new String(“1”) + new String(“1”);,这句会生成字符串常量池中的“1” 和 JAVA Heap 中的 s3引用指向的对象。中间还有2个匿名的new String(“1”)我们不去讨论它们。此时s3引用对象内容是”11”,但此时常量池中是没有 “11”对象的。
接下来s3.intern();这一句代码,不需要再存储一份对象了,可以直接存储堆中的引用。这份引用指向 s3 引用的对象。 也就是说引用地址是相同的。
最后String s4 = “11”; 这句代码中”11”是显示声明的,因此会直接去常量池中创建,创建的时候发现已经有这个对象了,此时也就是指向 s3 引用对象的一个引用。所以 s4 引用就指向和 s3 一样了。因此最后的比较 s3 == s4 是 true。
再看 s 和 s2 对象。 String s = new String(“1”); 第一句代码,生成了2个对象。常量池中的“1” 和 JAVA Heap 中的字符串对象。s.intern(); 这一句是 s 对象去常量池中寻找后发现 “1” 已经在常量池里了。
jdk1.7中的intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用.
另外两个字符串new String(“1”) + new String(“1”) 相加其实就等于调用StringBuilder.append进行拼接然后调用其
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
注意这个里面并没有new String(“11”)的操作,直接调用的是String的另外一个构造方法所以不会在字符串常量池中创建“11”这个字符串;
拓展
关于java字符串相加
String str1 ="a";
String str2 ="b";
String str3 = str1 + str2;
String str4 = "a" + "b";
//这两者实现过程不一样
很容易发现是str3通过StringBuilder类进行拼接得来的
str4是直接得来的,因此在字符串相加时候如果没有用到类似于str1之类的变量的话,就是直接拼接而来,否则就是另外一种情况了。
本文主要介绍Java中intern()方法,当调用该方法时,若字符串常量池中有对象则返回,没有则加入并返回引用。还对比了jdk1.6和jdk1.7中intern()方法的不同实现,解释了jdk7下特定字符串比较结果为true的原因,最后拓展了Java字符串相加的情况。
1328

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



