(Effective Java) equals를 재정의 할 때는 일반 규약을 따르라

*  Object.equals 를 재정의 하는 것이 바람직할 때는 언제인가?
-> 객체 동일성이 아닌 논리적 동일성의 개념을 지원하는 클래스 일 때,그리고 상위 클래스의  equals가 하위 클래스의 필요를 충족하지 못할 때 재정의 해야 한다. 값 클래스(value class)는 대체로 그 조건에 부합한다.
값 클래스는 Integer나 Date처럼, 단순히 어떤 값을 표현하는 클래스다.
객체에 대한 참조를 비교하는 프로그래머는 두 객체가 같은 값을 나타내는지를 알기 위해 equlals를 사용하지, 동일한 객체인지 보려고  equals를 호출하지 않는다.


<equals 메서드를 정의할 때 준수해야 하는 일반 규약(general Contract)>

->equals메소드는 동치 관계(equivalence relation)를 구현한다. 다음과 같은 관계를 동치관계라 한다.

  • 반사성(reflexive) : null이 아닌 참조 x가 있을 떄, x.equals(y)는 true를 반환한다.
  • 대칭성(symmetric) : null 이 아닌 참조 x와 y가 있을 때, x.equals(y) 는 y.equals(x)가 true일 때만 true를 반환한다.
  • 추이성(transitive): null 이 아닌 참조 x,y,z가 있을때, x.equals(y) 가 true이고 y.equals(z)가 true이면 x.equals(z)도 true이다.
  • 일관성(consistent): null이 아닌 참조 x와 y가 있을 때, equals를 통해 비교되는 정보에 아무런 변화가 없다면, x,.equals(y) 호출결과는 호출횟수에 상관없이 항상 같아야 한다.
  • null이 아닌 참조 x에 대해서, x.equals(null)은 항상 false이다.



->이것은 CaseInsetiveString의 equals에서는 String객체에 대해서는 알지만 String의 equals메소드는  CaseInsentiveString이 뭔지 모른다는 것이다. 그러므로 동치 관계 깨진다. 그러므로 다음과 같이 바꾸어야 한다.




<리스코프 대체 원칙>

어떤 자료형의 중요한 속성은 하위 자료형에도 그대로 유지되어서, 그 자료형을 위한 메소드는 하위 자료형에도 잘 동작해야 한다는 원칙이다.


그러므로 계승하는 대신 구성하는 것이 좋다.
즉, ColorPoint 클래스를 만들때 Point를 상속받기 보다는 







* abstract로 선언된 클래스에 값 필드를 추가하는 것은 equals 규약을 어기지 않고도 가능하다.


* equals규약의 네 번째 요구사항은, 일단 같다고 판정된 객체들은 추후 변경되지 않는 한 계속 같아야 한다는 것이다. 다시 말해, 변경 가능한 객체들(mutable objects)간의 동치 관계는 시간에 따라 달라질 수 있지만 변경 불가능 객체 사이의 동치관계는 달라질 수 없다.
클래스를 구현할 때 변경 불가능하도록 구현해야 하는지 깊이 생각해보라!!!!!!!
그리고 변경 가능 여부에 상관없이, 신뢰성이 보장되지 않는 자원(unreliable resource)들을 비교하는 equals를 구현하는 것은 삼가라.
예를들어, java.net.URL의 equals메소드는 URL에 대응되는 호스트의 IP주소를 비교하여 equals의 반환값을 결정한다. 문제는 호스트명을 IP주소로 변환하려면 네트워크에 접속해
야 하므로 언제나 같은결과가 나온다는 보장이 없다는 것이다. 따라서 URL의 equals메소드는 equals규약을 따르지 못한다.


* equals메소드의 인자형을 Object에서 다른것으로 바꾸지 마라
예) public Boolean equals(MyClass o){
...
}

댓글

이 블로그의 인기 게시물

(네트워크)폴링방식 vs 롱 폴링방식

(ElasticSearch) 결과에서 순서 정렬

(18장) WebSocekt과 STOMP를 사용하여 메시징하기