문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 | ||
java:equals_hashcode [2017/06/27 23:15] kwon37xi |
java:equals_hashcode [2017/07/04 01:06] (현재) kwon37xi [동치 문제의 최종 해결책 canEqual] |
||
---|---|---|---|
줄 1: | 줄 1: | ||
====== Java equals & hashCode ====== | ====== Java equals & hashCode ====== | ||
- | | + | * [[java: |
- | | + | |
* [[java: | * [[java: | ||
- | ===== 자주하는 equals & hashCode 실수 ===== | + | ===== 자주하는 equals & hashCode 실수 |
+ | * [[https:// | ||
==== 잘못된 '' | ==== 잘못된 '' | ||
<code java> | <code java> | ||
- | public boolean equals([ClassName] other) { | + | public boolean equals(ClassName other) { |
// 잘못된 equals!! | // 잘못된 equals!! | ||
} | } | ||
줄 17: | 줄 18: | ||
</ | </ | ||
+ | ==== equals가 변경되면 hashCode도 변경해야한다 ==== | ||
+ | * '' | ||
+ | * 그렇지 않으면 '' | ||
+ | * **hashCode 규약** | ||
+ | * 두 개의 객체가 '' | ||
+ | * '' | ||
+ | ==== Mutable(변경가능한) 필드에 대한 equals/ | ||
+ | * 변경가능한 필드에 대해 '' | ||
+ | * 이 상태로 필드 변경전에 HashSet에 값을 넣었다면, | ||
+ | |||
+ | ==== 동치(equivalence)를 위반해서는 안된다 ==== | ||
+ | '' | ||
+ | |||
+ | * 반사성(reflexive) : null이 아닌 x에 대해 '' | ||
+ | * 대칭성(symmetric) : null이 아닌 x, y에 대해, 오직 '' | ||
+ | * 이행성(transitive) : null이 아닌 x,y,z에 대해, '' | ||
+ | * 일관성(consistent) : null이 아닌 x, y에 대해, 객체의 동등성 비교에 사용된 정보에 변경이 없다면 '' | ||
+ | * null이 아닌 값 x 에 대해 '' | ||
+ | * [[https:// | ||
+ | |||
+ | 상속 관계에서는 위 동치성을 쉽게 위반하게 된다. '' | ||
+ | |||
+ | ==== 동치 문제의 최종 해결책 canEqual ==== | ||
+ | '' | ||
+ | 이를 통해 현재 클래스의 상위클래스와 동등하게 평가되는 것을 막을 수 있다. | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | |||
+ | <code java> | ||
+ | // Point 라는 클래스가 존재할 때 | ||
+ | |||
+ | public boolean canEqual(Object other) { | ||
+ | return (other instanceof Point); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public boolean equals(Object other) { | ||
+ | boolean result = false; | ||
+ | if (other instanceof Point) { | ||
+ | Point that = (Point) other; | ||
+ | // that.canEqual(this) 가 핵심이다. 이를 거꾸로 this.canEqual(that) 으로 사용하면 안된다. | ||
+ | result = (that.canEqual(this) && this.getX() == that.getX() && this.getY() == that.getY()); | ||
+ | } | ||
+ | return result; | ||
+ | } | ||
+ | |||
+ | // 오버라이드 되는 ColoredPoint 클래스에서는 | ||
+ | @Override | ||
+ | public boolean equals(Object other) { | ||
+ | boolean result = false; | ||
+ | if (other instanceof ColoredPoint) { | ||
+ | ColoredPoint that = (ColoredPoint) other; | ||
+ | result = (that.canEqual(this) && this.color.equals(that.color) && super.equals(that)); | ||
+ | } | ||
+ | return result; | ||
+ | } | ||
+ | |||
+ | // that.canEqual(this) 호출을 통해서 상위클래스(Point)는 결코 ColoredPoint와 같을 수 없게 보장됨. | ||
+ | @Override | ||
+ | public boolean canEqual(Object other) { | ||
+ | return (other instanceof ColoredPoint); | ||
+ | } | ||
+ | </ | ||
+ | * 프로그래머는 상위클래스에 '' | ||
===== 다른 타입간의 equals 탐지 ===== | ===== 다른 타입간의 equals 탐지 ===== | ||
* 서로 다른 타입간의 equals는 항상 '' | * 서로 다른 타입간의 equals는 항상 '' | ||
* [[java: | * [[java: | ||
* [[http:// | * [[http:// |