这是因为重载该方法不会改变诸如集合或其他equals(Object)显式使用该方法的地方的行为。例如,采用以下代码:
public class MyClass {
public boolean equals(MyClass m) {
return true;
}
}
如果你把它放在类似的东西中HashSet:
public static void main(String[] args) {
Set<MyClass> myClasses = new HashSet<>();
myClasses.add(new MyClass());
myClasses.add(new MyClass());
System.out.println(myClasses.size());
}
这将打印2, not 1,即使您希望所有MyClass实例从您的重载中都是相等的,并且该集合不会添加第二个实例。
所以基本上,即使这是true:
MyClass myClass = new MyClass();
new MyClass().equals(myClass);
这是false:
Object o = new MyClass();
new MyClass().equals(o);
后者是集合和其他类用来确定相等性的版本。事实上,这将返回的唯一true地方是参数明确是其子类型的实例MyClass或其子类型之一。
编辑:根据您的问题:
覆盖与重载
让我们从覆盖和重载之间的区别开始。通过覆盖,您实际上重新定义了方法。您删除了它的原始实现并用您自己的实际替换它。所以当你这样做时:
@Override
public boolean equals(Object o) { ... }
您实际上是在重新链接您的新equals实现以替换来自Object(或任何最后定义它的超类)的实现。
另一方面,当你这样做时:
public boolean equals(MyClass m) { ... }
您正在定义一个全新的方法,因为您正在定义一个名称相同但参数不同的方法。HashSet调用时equals,它会在以下类型的变量上调用它Object:
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
(该代码来自 的源代码HashMap.put,用作 的底层实现HashSet.add。)
需要明确的是,它使用不同的唯一时间equals是equals方法被覆盖,而不是重载。如果你尝试添加@Override到你的重载equals方法,它会因为编译器错误而失败,并抱怨它没有覆盖一个方法。我什至可以equals在同一个类中声明这两种方法,因为它重载:
public class MyClass {
@Override
public boolean equals(Object o) {
return false;
}
public boolean equals(MyClass m) {
return true;
}
}
泛型
至于泛型,不是equals泛型。它明确地作为它的类型,所以这一点没有实际意义。现在,假设您尝试这样做:Object
public class MyGenericClass<T> {
public boolean equals(T t) {
return false;
}
}
这不会与消息一起编译:
名称冲突:MyGenericClass 类型的方法 equals(T) 与 Object 类型的 equals(Object) 具有相同的擦除,但不会覆盖它
如果您尝试这样@Override做:
public class MyGenericClass<T> {
@Override
public boolean equals(T t) {
return false;
}
}
你会得到这个:
MyGenericClass 类型的方法 equals(T) 必须覆盖或实现超类型方法
所以你赢不了。这里发生的是 Java 使用擦除实现泛型。当 Java 在编译时检查完所有泛型类型时,实际的运行时对象都被替换为Object. 你所看到T的任何地方,都包含实际的字节码Object。这就是为什么反射不适用于泛型类以及为什么你不能做类似list instanceof List<String>.
这也使得您不能重载泛型类型。如果你有这个课程:
public class Example<T> {
public void add(Object o) { ... }
public void add(T t) { ... }
}
您将从该add(T)方法中获得编译器错误,因为当类实际完成编译时,这些方法将具有相同的签名,public void add(Object).