这是以前刚学Java那会经常被问到的问题,并且也会经常出现在面试中。这个问题不仅仅只局限于Java,可以适用于其他大部分语言,正好最近有个小朋友在学编程,特此整理一下。
String s1 = "abc" ;
String s2 = new String("abc");
首先,我们先看看以上两句分别做了什么?
String s1 = “abc” 做了什么
- 在栈中创建了一个名为 s1 的变量(引用)
- 如果 String池 中没有 “abc” 存在,则在常量池中创建一个 String 类型的 “abc” 对象,有就不创建
- 将 “abc” 的地址赋给 s1
所以,此句到底创建了几个对象,根据 “abc” 的情况而定,“abc” 之前存在就是一个,否则就没有创建。
String s2 = new String(“abc”) 做了什么
- 创建了一个名为 s2 的变量(引用)
- 如果 String池 中没有 “abc” 存在,则在 String池 中创建一个 String 类型的 “abc” ,有就不创建
- 使用 new关键字 在堆中创建了一个 String 对象
- 将用 new 创建的 String 对象的地址赋给 s2
所以,此句到底创建了几个对象,根据 “abc” 的情况而定,“abc” 之前存在就是1个,不存在就是2个。
栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中
堆:存放用 new 产生的数据
s1 == s2 与 s1.equals(s2)
s1 与 s2 看着都是内容为 “abc” 的字符串,但是使用 == 和 equals() 来判断它们是否相等时会发现,结果并不一样。
-
s1 == s2
结果为false
,根据上述内容我们可以知道,两者虽然内容一致,但是其实两者的指向的内存地址并不一致,而 == 会检查两者的内存地址是否一致,一致为true
,不一致为false
-
s1.equals(s2)
结果为true
,因为 equals() 在检查地址不相等后,还会检查两者的内容,两者内容相等,则仍然返回true
,毫无疑问,两者的内容是一致的。
关于 String s3 = “abc” + “xyz”;
还有一个与上述问题类似的问题,就是 String s3 = “abc” + “xyz”; 到底创建了几个对象?
关于 “abc” 与 “xyz” 在上述中已经提到,如果之前存在就不用创建,不存在则创建。我们更需要关心的是这两个字符串的拼接。
使用 “+” 拼接字符创,实际是创建了一个新字符串 “abcxyz”,所以至少会创建一个对象,如果 “abc” 与 “xyz” 之前都不存在,则就是创建3个对象,如果两个中只有一个存在,则是2个。
关于 = 符号的小拓展
对于 “=” 我们并不陌生,但是编程语言中的 “=” 我们不能单纯的当做数学中的等号,我们更习惯理解为赋值号,主要赋值的东西是内存地址,而不是内容本身。
我们可以这样粗暴的理解:当一个对象被创建出来时,它可以简单的分成两部份,地址与内容。当我们使用a = 对象
时,a 得到的并不是对象的内容,而是对象的地址,在我们操作 a 的时候,程序会通过 a(即对象的地址)来在内存中找到对象所表示的内容,并对其操作。
String a = "xyz";
String b = a;
System.out.println(" a = " + a);
System.out.println(" b = " + b);
a = "qwe";
System.out.println(" a = " + a);
System.out.println(" b = " + b);
打印结果:
a = xyz
b = xyz
a = qwe
b = xyz
那么在这过程中发生了什么?
- a 获取了 “xyz” 的内存地址
- a 将 “xyz” 的内存地址给了 b,此时 a 与 b的内存地址都是指向 “xyz”
- “qwe” 将它的地址赋给了 a,此时 a 的地址就指向 “qwe”,但是 b 仍然指向 “xyz”,所以 b 打印出来的值为 xyz。