Kilian Foth의 답변은 훌륭합니다. 이것이 왜 문제인지에 대한 정식 예제 *를 추가하고 싶습니다. 정수 포인트 클래스를 상상해보십시오.
class Point2D {
public int x;
public int y;
// constructor
public Point2D(int theX, int theY) { x = theX; y = theY; }
public int hashCode() { return x + y; }
public boolean equals(Object o) {
if (this == o) { return true; }
if ( !(o instanceof Point2D) ) { return false; }
Point2D that = (Point2D) o;
return (x == that.x) &&
(y == that.y);
}
}
이제 3D 포인트로 하위 클래스를 만들어 봅시다.
class Point3D extends Point2D {
public int z;
// constructor
public Point3D(int theX, int theY, int theZ) {
super(x, y); z = theZ;
}
public int hashCode() { return super.hashCode() + z; }
public boolean equals(Object o) {
if (this == o) { return true; }
if ( !(o instanceof Point3D) ) { return false; }
Point3D that = (Point3D) o;
return super.equals(that) &&
(z == that.z);
}
}
매우 간단합니다! 우리의 요점을 사용합시다 :
Point2D p2a = new Point2D(3, 5);
Point2D p2b = new Point2D(3, 5);
Point2D p2c = new Point2D(3, 7);
p2a.equals(p2b); // true
p2b.equals(p2a); // true
p2a.equals(p2c); // false
Point3D p3a = new Point3D(3, 5, 7);
Point3D p3b = new Point3D(3, 5, 7);
Point3D p3c = new Point3D(3, 7, 11);
p3a.equals(p3b); // true
p3b.equals(p3a); // true
p3a.equals(p3c); // false
내가 왜 그렇게 쉬운 예를 게시하는지 궁금 할 것입니다. 다음은 캐치입니다.
p2a.equals(p3a); // true
p3a.equals(p2a); // FALSE!
2D 점을 동등한 3D 점과 비교하면 true가되지만 비교를 반대로하면 p2a가 실패하기 때문에 false가 instanceof Point3D
됩니다.
결론
일반적으로 수퍼 클래스가 작동하는 방식과 더 이상 호환되지 않는 방식으로 서브 클래스에서 메소드를 구현할 수 있습니다.
부모 클래스와 호환되는 방식으로 크게 다른 서브 클래스에서 equals ()를 구현하는 것은 일반적으로 불가능합니다.
사람들이 서브 클래스를 만들도록 허용하는 클래스를 작성할 때 각 방법의 작동 방식에 대한 계약 을 작성하는 것이 좋습니다 . 더 나은 방법은 사람들이 계약을 위반하지 않음을 입증하기 위해 재정의 된 메소드 구현에 대해 실행할 수있는 단위 테스트 세트 일 것입니다. 너무 많은 일이기 때문에 아무도 그렇게하지 않습니다. 하지만 걱정한다면해야 할 일입니다.
잘 작성된 계약의 좋은 예는 Comparator 입니다. .equals()
위에서 설명한 이유로 말한 내용 을 무시하십시오 . 다음은 Comparator가 할 .equals()
수없는 일 을 수행하는 방법에 대한 예입니다 .
노트
Josh Bloch의 "Effective Java"항목 8이이 예제의 소스이지만 Bloch는 ColorPoint를 사용하여 세 번째 축 대신 색상을 추가하고 int 대신 double을 사용합니다. Bloch의 Java 예제는 기본적으로 Odersky / Spoon / Venners에 의해 복제되어 예제를 온라인으로 제공합니다.
부모 클래스에 하위 클래스에 대해 알리면이 문제를 해결할 수 있기 때문에 여러 사람들이이 예제에 반대했습니다. 충분히 적은 수의 하위 클래스가 있고 부모가 모든 하위 클래스를 알고 있으면 사실입니다. 그러나 원래의 질문은 다른 누군가가 서브 클래스를 작성할 API를 만드는 것에 관한 것입니다. 이 경우 일반적으로 하위 구현과 호환되도록 상위 구현을 업데이트 할 수 없습니다.
보너스
Comparator는 equals ()를 올바르게 구현하는 문제를 해결하기 때문에 흥미 롭습니다. 더 나은 방법은이 유형의 상속 문제를 해결하기위한 패턴 인 전략 디자인 패턴을 따르는 것입니다. Haskell과 Scala 사람들이 열광하는 Typeclass도 전략 패턴입니다. 상속은 나쁘거나 잘못이 아니며 까다 롭습니다. 자세한 내용은 Philip Wadler의 논문 을 참조하십시오. ad-hoc 다형성을 ad ad hoc로 만드는 방법