반응형
[Effective Java] equals 메소드를 오버라이딩 할 때는 보편적 계약을 따르자. |
인스턴스의 동일 여부를 판정하는 equals 메소드의 오버라이딩은 간단한 것 같지만, 잘못되는 경우가 많아서 참담한 결과를 초래할 수 있다.
( 기본 equals 는 참조를 비교한다. )
-
다음의 조건이 만족된다면 슈퍼 클래스의 equals 를 그냥 사용해도 된다.
1. 클래스의 각 인스턴스가 본래부터 유일한 경우.
2. 두 인스턴스가 논리적으로 같은지 검사하지 않아도 되는 클래스의 경우.
3. 수퍼 클래스에서 equals 메소드를 이미 오버라이딩 했고, 그 메소드를 그대로 사용해도 좋은 경우.
4. private 이나 패키지 전용(package private) 클래스라서 이 클래스의 equals 메소드가 절대 호출되지 않아야 할 경우.
( 이 경우에는 AssertionError 를 throw 하는 것이 더 좋다. )
-
equals 는 인스턴스가 갖는 값을 기준으로 논리적으로 같은지 판단할 필요가 있을 때 사용된다.
Map 의 key 나 Set 의 element 로 객체를 저장하고 사용할 수 있게 하려면 equals 메소드의 오버라이딩이 꼭 필요하다.
-
equals 를 오버라이드 할 때 다음 보편적 계약을 따라야 한다. ( null 이 아님에 대해 )
1. 재귀적이다. ( reflexive )
x.equals(x) == true
2. 대칭적이다. ( symmetric )
y.equals(x) == x.equals(y)
3. 이행적이다. ( transitive )
x.equals(y) == y.equals(z) == x.equals(z)
4. 일관적이다. ( consistent )
x.equals(y) 는 값이 변경되지 않으면 항상 일정
5. x.equals( null ) 은 반드시 false 를 반환.
-
양질의 equals 메소드를 만드는 방법은 다음과 같다.
1. 객체의 값을 비교할 필요 없고 참조만으로 같은 객체인지 비교 가능하다면 == 연산자를 사용하자.
2. instanceof 연산자를 사용해서 전달된 인자가 올바른 타입인지 확인하자. 그렇지 않다면 false 를 반환한다. 클래스가 구현하는 인터페이스도 올바른 타입이 될 수 있다.
3. 인자 타입을 올바른 타입으로 변환한다.
4. 클래스의 중요한, 꼭 비교해야 하는 필드 각각에 대해서는 인자로 전달된 객체의 필드와 현재 객체의 필드가 모두 같은지 빠뜨리지 말고 비교한다.
float, double 타입이 아닌 기본형은 == 로 비교하고, 필드가 객체일 때는 equals 로 비교한다.
float, double 의 경우 각각 Float.compare 과 Double.compare 로 비교해야 한다.
float 과 double 은 각각 Float.NaN, -0.0f 과 Double.NaN, -0.0 값이 나올 수 있기 때문이다.
float 과 double 은 각각 Float.NaN, -0.0f 과 Double.NaN, -0.0 값이 나올 수 있기 때문이다.
5. 참조필드가 null 일 가능성은 항상 발생하는데 다음 이디엄을 사용하면 좋다.
(field == null ? o.field == null : field.equals(o.field))
(field == o.field || (field != null && field.equals(o.lfield)) // 성능이 더 좋다.
(field == null ? o.field == null : field.equals(o.field))
(field == o.field || (field != null && field.equals(o.lfield)) // 성능이 더 좋다.
6. 성능향상을 위한다면, 다를 가능성이 가장 많거나 비교 비용이 적게 드는 필드부터 먼저 비교한다.
7. equals 메소드를 작성한 후에는 대칭적, 이행적, 일관성을 갖는지 확인한다.
-
equals 메소드를 오버라이드 할 때는 hashCode 메소드도 항상 오버라이드 해야 한다.
-
너무 똑똑한 척 해서 쓸데없는 비교나 잘못된 비교를 하기 쉬우니 이것도 조심한다.
-
equals 메소드의 인자 타입을 Object 대신 다른 타입으로 바꾸지 말자.
반응형
'프로그래밍 놀이터 > 디자인 패턴, 리펙토링' 카테고리의 다른 글
[Effective Java] equals 메소드를 오버라이드 할 때는 hashCode 메소드도 항상 같이 오버라이드 하자. (0) | 2016.10.05 |
---|---|
[Effective Java] 쓸모 없는 객체 참조를 제거하자. (0) | 2016.01.04 |
[Effective Java] Chap 3. 모든 객체에 공통적인 메소드. (0) | 2015.12.23 |
[Effective Java] 파이날라이저 ( finalizer ) 의 사용을 피하자. (0) | 2015.12.15 |
[Effective Java] 불필요한 객체의 생성을 피하자. (0) | 2015.04.30 |
댓글