我最近遇到了一个有趣的行为.似乎如果我重写.equals()来获取除Object之外的参数,它就不会被调用.任何人都可以向我解释为什么会这样吗?这似乎违反了我对OOP中多态性的理解,但也许我错过了一些东西.
这里有更简单的代码,显示了我所看到的内容:
public class MyClass { private int x; public MyClass(int n) { x = n; } public boolean equals(Object o) { return false; } public boolean equals(MyClass mc) { return x == mc.x; } public static void main(String[] args) { Listlist = new ArrayList (); list.add(new MyClass(3)); System.out.println("Contains 3? " + list.contains(new MyClass(3))); } }
运行时,它会打印" Contains 3? false
".它看起来像是调用了equals(Object)函数,即使有另一个函数可以工作.相比之下,如果我写这样的equals代码按预期工作:
public boolean equals(Object o) { if(!(o instanceof MyClass)) return false; MyClass mc = (MyClass)o; return x == mc.x; }
为什么不根据参数的类型确定要调用哪个版本的函数?
你混淆了"覆盖"和"超载".
覆盖 - 为了多态而添加现有方法的替换定义.该方法必须具有相同的签名.签名由名称和参数类型组成.根据目标对象的运行时类型在运行时选择重写的方法.
重载 - 添加具有相同名称但具有不同签名的方法.根据目标对象的编译时类型,在编译时选择重载方法.
equals(Object)覆盖了一个超级方法; 你不能在不使用完全相同的签名的情况下覆盖超级方法(嗯,有一些例外,如协变返回类型和异常).
请注意,您调用的方法是在ArrayList
boolean contains(Object o) Returns true if this list contains the specified element.
代替
boolean contains(E o) Returns true if this list contains the specified element.
ArrayList.java的实现:
private transient Object elementData[]; public boolean contains(Object elem) { return indexOf(elem) >= 0; } public int indexOf(Object elem) { if (elem == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (elem.equals(elementData[i])) return i; } return -1; }
它使用Object超类中定义的equals方法,因为在ArrayList
在java中重写Object equals时,您也应该重写Object hashCode方法.
无论如何,您可能想尝试以下代码:
class A{ public int content; A(){ this(0); } A(int value){ content = value; } public boolean equals(Object obj){ System.out.println("overriding equals method"); return this.content == ((A) obj).content; } public boolean equals(A a){ System.out.println("overloading equals method"); return this.content == a.content; } public static void main(String[] args){ A x = new A(1); A y = new A(2); Object z = new A(1); System.out.println(x.equals(y)); System.out.println(x.equals(x)); System.out.println(x.equals(z)); //override as z is declared as Object at compile time //so it will use methods in class Object instead of class A System.out.println(x.equals((Object) y)); System.out.println(x.equals((Object) x)); } } //rant: they didn't teach me these in javaschool and I had to learn it the hard way.