【这个知识点是面试中的一个经久不衰的问题】
创建字符串对象的两种方式:【直接赋值】和【使用构造方法创建】
这两种方式创建的字符串在内存分配上存在不同,所以导致我们【==】进行字符串比较的时候存在差异。
字面量创建字符串对象
public class Hello {
public static void main(String[] args) {
//声明两个字符串对象
String s1="abcd";
String s2="abcd";
System.out.println(s1==s2);
}
}
true,说明s1和s2在同一块内存空间。
【==】比较的是对象的内存地址。
在使用直接赋值的方式创建字符串的时候字符串对象是保存在一块叫做【String常量池】的空间中。在实例化字符串之前会先到String常量池中查看要创建的字符串是否已经存在。
public class Hello {
public static void main(String[] args) {
//声明两个字符串对象
String s1="abcd";//第一行,会到常量池检测是否存在,目前不存在,则在String常量池中创建该对象并且返回引用赋值给s1
String s2="abcd";//第二行,会到常量池中检测“abcd”是否存在,第一行创建了,所以存在,于是不再创建该字符串了,直接返回已经存在的“abcd”的引用给s2
System.out.println(s1==s2);//所以最后s1和s2都指向常量池中的“abcd”字符串对象。
}
}
使用new关键字创建字符串对象
public class Hello {
public static void main(String[] args) {
//声明两个字符串对象
String s1=new String();
String s2=new String();
System.out.println(s1==s2);
}
}
false,说明了s1和s2指向的不是同一个对象的内存地址,这是因为使用new关键字实例化字符串对象的特征决定的。
当使用new关键字实例化对象的时候:
public class Hello {
public static void main(String[] args) {
//声明两个字符串对象
String s1=new String();//第一行,先到常量池中查找是否有“abcd”,此时没有,则在常量池中创建一个“abcd”对象,之后再到堆内存中创建“abcd”对象,返回的引用是堆内存中的“abcd”对象的内存地址,之歌过程中一共创建了两个对象
String s2=new String();//第二行,先到常量池中查找是否有“abcd”,此时有了,则不再到常量池中创建,只是再堆内存中创建一个“abcd”对象。这个过程创建了一个对象.
System.out.println(s1==s2);//最后结果s1和s2指向的堆内存中的两个独立的字符串对象。
}
}
总结:
1.字面量创建对象:
先到String常量池中查找是否存在,如果存在则直接返回引用,如果不再则创建之后返回引用。
2.使用构造方法实例化对象
先到常量池中查找是否存在,如果存在则在堆内存中创建一个返回引用即可,如果不存在则在常量池中创建一个对象,之后再到堆内存创建一个内容相同对象再返回引用。