Java에서 동일하게 재정의 할 때 왜 객체 이외의 매개 변수를 사용하는 것이 작동하지 않습니까?
-
08-07-2019 - |
문제
나는 최근에 흥미로운 행동을 취했다. 객체 이외의 다른 매개 변수를 가져 오도록 .equals ()를 재정의하면 호출되지 않는 것 같습니다. 누구든지 왜 이런 일이 일어나고 있는지 설명 할 수 있습니까? 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) {
List<MyClass> list = new ArrayList<MyClass>();
list.add(new MyClass(3));
System.out.println("Contains 3? " + list.contains(new MyClass(3)));
}
}
이것이 실행되면 인쇄 "Contains 3? false
". 이는 작동하는 또 다른 것이 있지만 평등 (객체) 함수가 호출되는 것처럼 보입니다. 대조적으로, 이와 같이 똑같이 작성하면 코드는 예상대로 작동합니다.
public boolean equals(Object o) {
if(!(o instanceof MyClass))
return false;
MyClass mc = (MyClass)o;
return x == mc.x;
}
매개 변수 유형에 따라 어떤 버전의 호출을 호출할지 알아 내지 않는 이유는 무엇입니까?
해결책
"재정의"와 "과부하"를 혼합하고 있습니다.
재정의 - 다형성 목적을위한 기존 방법의 대체 정의 추가. 이 메소드는 동일한 서명이 있어야합니다. 서명은 이름과 인수 유형으로 구성됩니다. 대상 객체의 런타임 유형에 따라 런타임에서 재정의 메소드가 선택됩니다.
오버로드 - 이름이 같지만 서명이 다른 메소드를 추가합니다. 과부하 된 방법은 대상 객체의 컴파일 시간 유형에 따라 컴파일 시간에 선택됩니다.
다른 팁
Equals (Object)는 슈퍼 방법을 재정의하고 있습니다. 당신은 할 수 있습니다 ~ 아니다 정확히 동일한 서명을 사용하지 않고 슈퍼 메소드를 대체하십시오 (음, 공분산 반환 유형 및 예외와 같은 예외가 있습니다).
호출중인 메소드는 arraylist를 위해 Javadoc에 정의됩니다.<E
> AS
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;
}
arraylist에서 equals 메소드가 재정의되지 않으므로 객체 슈퍼 클래스에 정의 된 Equals 메소드를 사용합니다.<E
>의 구현.
객체를 재정의하는 것이 Java에서 동일하면 객체 해시 코드 메소드도 무시해야합니다.
어쨌든 다음 코드를 시도하고 싶을 수도 있습니다.
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.
다른 유형이 있습니다 http://en.wikipedia.org/wiki/polymorphism_(computer_science). 자바는하지 않습니다 http://en.wikipedia.org/wiki/double_dispatch.
포함 (개체) 메소드의 ArrayList 구현은 내부적으로 Object.equals (Object) 메소드를 사용해야하므로 Equals (MyClass) 메소드의 과부하에 대해서는 알 수 없습니다. 우선적 인 메소드 (일치하는 서명) 만 발견됩니다.
알았어.
(1) 컴파일러가 제네릭에 관한 모든 정보를 제거하기 때문에 (삭제, 여기), 및 (2) 정확히 동일한 서명없이 메소드를 무시할 수 없기 때문에 (Equals (Object)), (3) 런타임 동안 목록 내의 모든 객체는 MyClass의 인스턴스가 아닌 개체로 취급됩니다. 따라서 호출되는 방법은 동일 (객체)입니다. 왜냐하면 이것은 수업에 의해 덮어 쓴 것이기 때문입니다.
당신은 그것을 가정하고 있습니다 contains()
방법 List
런타임시 객체의 유형을 알고 있습니다.
삭제 때문에 List<MyClass>
단지 규칙이됩니다 List
런타임에 contains()
메소드는 매개 변수를 an으로 본다 Object
, 따라서 객체를 호출합니다 equals()
당신이 정의한 것 대신 MyClass
실행 중.