问题
实际使用时,可能出现==和equals比较结果不一致的情况,以String为例,测试代码如下:
public static void main(String[] args) {
String str1 = "123";
String str2 = "123";
String str3 = new String("123");
String str4 = new String("123");
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str3 == str4);
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str3.equals(str4));
}
对于上面一段代码输出结果为:
true
false
false
true
true
true
可以看到实际使用==作比较时,有可能出现输出结果不符合预期和逻辑的情况。
二者异同
==
如果比较的对象是引用类型,则直接比较二者地址,地址相同时返回true,不同时返回false,所以上文代码用==比较输出false的根本原因就是两个对象的内存地址不同。
equals
在判断两个对象是否相等时,不同的类有不同的判别标准是合理的,所以不应该设立一个统一的标准供对象们进行比较,因此Object类提供了一个equals方法,在Object类下的equals方法直接返回使用==的比较结果,实际上使用的时候可供各子类自行重写,实现适合类的比较方式。
public boolean equals(Object obj) {
return (this == obj);
}
下面以String和Array为例分析String.equals()做了哪些比较。
String的equals方法
String下的equals源码如下:
public boolean equals(Object anObject) {
//首先比较地址 相同则直接返回true
if (this == anObject) {
return true;
}
//再判断入参是否是当前类的子类
//由于String被final修饰不能被继承 此处实际就是判断anObject是否是String对象
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
//再判断两个String对象的value长度是否相同
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
//逐位比较value值
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Arrays的equals方法
Arrays中用于比较int型数组的方法源码如下:
public static boolean equals(int[] a, int[] a2) {
//仍然先直接比较地址
if (a==a2)
return true;
if (a==null || a2==null)
return false;
//再比较数组长度
int length = a.length;
if (a2.length != length)
return false;
//最后逐位比较
for (int i=0; i<length; i++)
if (a[i] != a2[i])
return false;
return true;
}
总结
- ==直接比较两对象的内存地址,不关注对象本身。
- equals由Object类提供,Object类内的equals等效于==,equals方法由子类进行重写,不同类内具体实现不同,在开发过程中如果类的判等有特殊条件,应重写equals方法以提供适合的比较手段。