JavaStudy

ITEM8 : equals 메소드를 오버라이딩 할때는 보편적 계약을 따르자.

  • equals 메소드를 오버라이딩 하지 않는게 되도록 좋다. 특별한경우 가 아니라면!

    • 클래스의 각 인스턴스가 본래부터 유일한 경우 : Thread 와 같은 클래스 처럼 값의 논리적인 비교는 의미가 없으며 객체 참조가 같으면(==) 동일한 것임을 알 수 있기 때문에
    • 두 인스턴스가 논리적으로 같은지 검사하지 않아도 되는 클래스의 경우 : java.util.Random 과 같은 클래스, equals 같은 기능이 필요가없다.
    • 수퍼 클래스에서 equals 메소드를 이미 오버라이딩 했고 그 메소드를 그대로 사용해도 좋은경우 : Set 의 AbstractSet, List 의 AbstractList
    • private 이거나 package 전용 클래스라서 이클래스의 equals 메소드가 절대 호출되지 않아야 할 경우.

      @Override public boolean equals(Object o){
         throw new AssertionError(); // 에러를 발생 시켜준다.
      }
      
    • 특별한 경우 오버라이딩 되도록 해도 좋다. Value 클래스 같은경우 하나의 값을 나타내는 클래스로써 Integer Date와 같은것들이다. 같은 객체 참조 여부는 중요하지 않고 객체가 갖는 값이 논리적으로 같은지가 관심있는 클래스의 경우다. Map 이나 Set 의 요소로 사용될경우 equals 메소드의 오버라이딩이 꼭 필요하다. 같은 값의 객체가 이미 있는지 비교하는 수단을 제공해야 되기 떄문이다.

  • equals 메소드가 만족해야 하는 속성

    • 재귀성 : null 아닌 x.equals(x) 반드시 true 여야한다.
    • 대칭성 : null 아닌 x.quals(y) 이면 반대로 true다!
    • 이행성 : x.equals(y) y.equals(z) 이면 x.equals(z) 여야한다.
    • 일관성 : 한번 같으면 계속 같아야한다.
  • 상속을 사용할경우 완벽한 equals 를 구현하기 힘들다. 차라리 Composition( 변수로 선언 ) 을 하는것이 좋다.

    • java.sql.Timestamp 는 java.util.Date 로 상속받아 구현되어있다. Timestamp 와 date 을 eqauls 할경우 대칭성을 위한하고 있어서 같이 혼용되어 사용하면 엉뚱한 결과를 초대할수 있다.
    • Abstract 클래스의 서브클래스에는 eqauls 계약을 위배 하지 않고 값 컴포넌트를 추가할수 있다.
  • 상속을 이용해 equals 를 구현하려면 instanceof 키워드를 사용해 체크해주는것이 좋다.
  • float double 이 아닌 기본 필드경우에는 == 연산자로 비교하며 필드가 객체 참조일때는 eqauls 메소드를 재귀적으로 다시 호출한다. Float 객체의 경우 Float.compare Dobule 은 Double.compare 메소드를 사용한다.(floating point problem) Float.eqauls 나 Double.equals 를 사용해도 된다. 객체가 null 을 가질수도 있으므로

       (field == null ? o.field == null field.equals(o.field))
    
  • equals 메소드의 인자타입을 Object 대신에 다른 타입으로 바꾸지 말자! 무조건 기본형을 오버라이딩 하자. 변수타입을 바꿔 오버로드 하면 가끔은 성능향상을 가져올수 있지만 코드만 복잡하게 할 뿐이다. 이런 실수를 줄이기 위해 equals 함수에는 무조건 @Override 키워드를 사용해 주는것이 좋다.