首先,我们需要明白三个词的概念:栈,堆,字符串常量池。
- 栈区:存放的是基本类型和引用类型的引用地址,不能存对象;
- 堆区:存放对象;
- 字符串常量池:在方法区,是独立于栈和堆的存储空间,用于存放常量;
然后,我们分别简述下他们的实现过程:
1. String str1 = "Jimmy" :
首先 JVM 在栈区创建 str1 的引用,然后在"字符串常量池"中寻找是否已经存在其指向的内容为"Jimmy"的对象,如果"字符串常量池"中有,则直接将 str1 的引用指向常量池中的"Jimmy"对象;如果没有,则创建一个新的,然后将 str1 的引用指向"字符串常量池"中的对象;
- 如果后来又定义了字符串变量 str2 = "Jimmy",则直接将 str2 的引用指向"字符串常量池"中已经存在的"Jimmy"对象,不再重新创建新的对象;
- 当 str1 进行了新的赋值(如:str1 = "Jim"),则 str1 将不再指向"Jimmy",而是重新指向"字符串常量池"中的 "Jim"。
- 此时如果定义 String str3 = "Jim",进行 str1 == str3 操作,返回值为true,因为他们的值一样,地址一样;但是如果内容为 "Jim" 的 str1 进行了字符串的连接 str1 = str1+"my",此时 str1 指向的是在堆中新建的内容为"Jimmy"的对象,即此时进行str1 == str2,返回值 false,因为他们的地址不一样。
上述分析的案例:
@Test
public void test(){
String str1 = "Jimmy";
String str2 = "Jimmy";
System.out.println(str1 == str2); // true
str1 = "Jim";
String str3 = "Jim";
System.out.println(str1 == str3); // true
str1 = str1+"my";
System.out.println("str1 = " + str1); // str1 = "Jimmy"
System.out.println(str1 == str2); // false
}
2. String str1 = new String("Jimmy") :
直接在堆中创建对象(new一个对象,可以理解为“我需要一个全新的对象”);
- 如果又有 String str2 = new String("Jimmy"),那么 str2 不会指向之前的对象,而是重新创建一个新的对象并指向它,两个对象的地址不一样,所以此时 str1 == str2 返回值是 false;
- 而此时 str1.equals(str2) 返回值是 true,因为 String 重写了 Object 的 equals() 方法,比较的是内容是否相同。
上述分析的案例:
@Test
public void test(){
String str1 = "Jimmy";
String str2 = new String("Jimmy");
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
}
更多精彩,请关注我的"今日头条号":Java云笔记
随时随地,让你拥有最新,最便捷的掌上云服务