引言:在理解equals和==的区别之前,必须先搞懂 栈和堆之间的区别。
总的来说:
值类型是存储在内存中的栈中,而引用类型的变量在栈中存储的仅仅是引用类型变量的地址,而引用类型本身是存储在堆中。
equals 和 == 的区别:
- == 操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同。
- equals操作表示的是两个变量是否是对同一个对象的引用,即堆中的内容是否相同。
- 更简单的说法:==比较的是地址,equals比较的是内容
例子:字符串的比较
public class EqualsTest {
public static void main(String[] args){
String s1 = "Test";
String s2 = "Test";
System.out.println("s1 == s2 : " + (s1 == s2));
System.out.println("s1.equals(s2): " + s1.equals(s2));
}
}
输出结果:
s1 == s2 : true
s1.equals(s2): true
接下来,做些改动:将s2通过new的方式来创建
public class EqualsTest {
public static void main(String[] args){
String s1 = "Test";
String s2 = new String("Test");
System.out.println("s1 == s2 : " + (s1 == s2));
System.out.println("s1.equals(s2): " + s1.equals(s2));
}
}
输出结果:
s1 == s2 : false
s1.equals(s2): true
我们发现这时候==操作结果为false了,equals方法依旧不变。
实际上,这是字符串缓冲池所起的作用。当我们在创建s1字符串后,s1便存放在字符串缓存池中。
- 对于第一种情况,创建s2时,程序会在缓冲池中寻找到具有相同值的s1,因此s2和s1共同引用对象"Test"。也就是说s1和s2的引用地址相同,那么自然引用对象也是相同的咯。所以两者都为true。
- 对于第二种情况,我们通过new方式创建了s2,相当于告诉程序“我要个新的,不要旧的”。因此,程序会重新创建一个"Test"对象在内存中,虽然它们的值相同,但它们的位置是不同的。因此,它们的引用地址自然是不同的,==操作自然为false,equals为true,因为它们的内容还是相同的。
当然,如果我们希望s2是从缓冲池中拿到对象,可以调用intern()方法实现:
public class EqualsTest {
public static void main(String[] args){
String s1 = "Test";
String s2 = new String("Test").intern();
System.out.println("s1 == s2 : " + (s1 == s2));
System.out.println("s1.equals(s2): " + s1.equals(s2));
}
}
输出结果:
s1 == s2 : true
s1.equals(s2): true
也就是说,通过intern()方法防止了程序创建重复的对象。
总结:
- == 比较的是两个对象的地址,而equals比较的是两个对象的内容。
- 地址相同的两个对象自然内容也是相同的,即满足==为true,则equals必然为true。但注意对象内容相同的,地址不一定相同,因此,满足equals为true,但==不一定为true。
网友评论