一转眼好几天都没有写些什么东西了,今天正好周末,我们就聊聊==和equals使用时的那些事情吧。
==和equals的区别是什么?
有一点Java基础的人都会回答,==是基于内存地址的比较,equals()是基于对象内容的比较。
但事情就真的就这么简单吗? 上一段测试代码
public class Animal {
public String name;
public Integer age;
public Animal() {
}
public Animal(String name, Integer age) {
this.name = name;
this.age = age;
}
}
public static void main(String[] args) {
Animal animal1 = new Animal("1", 1);
Animal animal2 = new Animal("1", 1);
if (animal1.equals(animal2)) {
System.out.println("==");
} else {
System.out.println("!=");
}
}
运行截图截图
可能很多人都开始觉得自己眼睛花,觉得运行逻辑有问题,但事实就是这样,无从辩驳。即使是事实,我们就应该像一个学者一样探究客观事实背后的真相,这里就牵涉到Java的一些隐藏的世界观。
在Java里面,如果没有显示的继承(extends)某个类,那么就会默认继承(extends)Object这个超类(父类、基类),这是由JVM保证的强制规则(PS:网上的一些文章说的是编译器保证,这个刚才亲自测试了一下,反编译.class文件,没有看到默认继承的,版本:java version “1.8.0_161”,Java(TM) SE Runtime Environment (build 1.8.0_161-b12),Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode),这个可以自己测试),在自己不重写(Override)的情况下,会默认调用父类对应的方法。
public boolean equals(Object obj) {
return (this == obj);
}
在Object里面,equals()就是直接用的==判断。
equals是基于内容比较的说法从何而来?
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
这是String类里面的equals(),而equals()是基于内容来比较的说法也源自这里。可以明显的看出,equals()是重写(Override)过的,也可以看出为什么说是基于内容来比较。在Java里面很封装类都自己重写了equals(),所以给人造成一种错觉,==是基于地址比较,equals是基于内容比较。这种说法不能说错,但也算不上正确。虽然很多类都重写的equals(),不过有部分封装类比较的时候会出现意料之外情况,比如:Integer、Enum一类。这个时候应该基于对应的版本去看源码实现吧,我一直觉得阅读源码才是最快的理解方式。
基于上面的讲述,你对==和equals()应该有所了解,对使用这两者的场合应该有着更清晰的定义,要实现自定义封装数据类型的比较,需要重写自己的equals()。这点很重要,不然还是会默认调用==。
现在讲讲重写(Override)equals()的注意事项:
1、自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
2、对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
3、传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
4、一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
5、对于任何非空引用值 x,x.equals(null) 都应返回 false。
上述所说是在Java规范中要求的,只是一种强制,没有强制要求。如果不遵守这些规范,使用equals()会出现一些意想不到的错误,官方没有给出具体说明。程序开发是一个团队活动,该遵守的规范还是应该遵守的。
两者最本质的区别还是:==是一种操作符运算,而equals()是一个类方法的。