一、Java中两种创建字符串对象的方式
public static void main(String[] args) {
//使用字面值创建s1对象,对象实例存放于常量池;
String s1 = "1";
//使用new关键字创建s2对象,对象实例存放于堆中;
String s2 = new String("1");
}
s1对象创建过程解析:把字符串直接量的值传入常量池中,并把常量池中s1实例对象的地址返回给s1对象;
s2对象创建过程解析:在常量池中查找是否有s1对象的值。若有,则在堆中创建s2实例,并返回s2实例在堆中的地址;若无,则先在常量池中创建s2对象的值,之后在堆中创建s2对象的实例,并返回s2对象实例的地址;
为上述的内容验证代码如下
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);
//输出的结果是true表示在常量池中地址相等;
String s3 = new String("xyz");
String s4 = new String("xyz");
System.out.println(s3==s4);
//输出false,表示在堆中的地址不同
二、intern()方法的调用;
如果在常量池中有字符串的值,则把常量池中字符串的地址返回;
如果常量池中没有字符串的值,则在堆中查找。若有,则返回堆中的地址,并且把堆中的地址引用到常量池中;
如果常量池和堆中都没有,则将当前字符串复制到字符串常量池中,并返回字符串常量池中的引用;
String s1 = 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);
输出结果为 false true
String s1 = new String(“1”); 在字符串常量池中创建"1"对象,在堆中创建s对象。
s.intern(); 由于字符串常量池中已经有"1"对象,因此该句并无实际意义。
s2指向字符串常量池中"1"对象。
因此s指向堆中的引用,s2指向字符串常量池中的引用,返回 false。
s3.intern(); 先在字符串常量池中查找是否存在"11",再从堆中查找,然后将堆中s3的引用存储到字符串常量池中。
String s4 = “11”; 创建的时候发现字符串常量池中有了“11”(s3),然后指向s3引用的对象。
因此s3与s4的引用相同,返回 true。
三、JDK6和JDK7的不同
JDK6的常量池在"永久代"中,JDK7的常量池在堆中;
JDK6中只能查询或创建在字符串常量池;
JDK7中会先查询字符串常量池,若没有又会到堆中再去查询并存储堆的引用,然后返回;