티스토리 뷰

이펙티브 자바 Effective Java 2/E
국내도서
저자 : 조슈아 블로크(Joshua Bloch) / 이병준역
출판 : 인사이트 2014.09.01
상세보기


equals 를 메소드를 재정의할때는 실수할 여지가 많지만 그렇다고 재정의하지 않기에는 객체는 자기 자신과만 동일하기 때문에 불편함이 따른다.

객체가 자기 자신과만 동일한 equals 메서드를 사용해도 되는 경우. 아래 가운데 하나만 만족한다면 
equals 메서드를 재정의 하지 않아도 된다.

1 .각각의 객체가 고유하다
 => 값(value) 대신 활성 개체(active entitiy)를 나타내는 Thread 같은 클래스가 이 조건에 부합하다.

2. 클래스에 "논리적 동일성(logical equality)" 검사 방법이 있건 없건 상관없다.
=> Random 클래스를 설계한 사람은 클라이언트가 그런 기능을 원할거라 생각하지 않았기 때문에 
구현하지 않았다. 이런 경우에 구현하지 않아도 된다.

3. 상위 클래스에서 재정의한 equals가 하위 클래스에서 사용하기에도 적당하다.

4. 클래스가 private 또는 package-private로 선언되었고, equals 메서드를 호출할 일이 없다.

5. 개체 통제 기능을 사용해 값마다 최대 하나의 객체만 존재하도록 제한하는 클래스
=> 값마다 객체가 오로지 하나만 존재하기 때문에 equals를 사용해서 비교 가능.

equals를 재정의하는 것이 바람직한 경우.

1. 객체 동일성이 아닌 논리적 동일성의 개념을 지원하는 클래스

2. 상위 클래스의 equals가 하위 클래스의 필요를 충족하지 못할 경우.

equals의 5가지 규약

1. 반사성 (Reflexivity)
=>모든 객체는 자기 자신과 같아야 한다.

2. 대칭성 (Symmetry)
=> 예제를 통해 설명한다. 이 클래스는 대소문자 구별 없는 문자열을 나타내고 toString 결과물에는 대소문자가 제대로 찍히지만, 비교할 때만 무시한다.

public final class CaseInsensitiveString { private final String s; public CaseInsensitiveString(String s) { if (s == null) { throw new NullPointerException(); } this.s = s; } //대칭성 위반 @Override public boolean equals(Object o) { if (o instanceof CaseInsensitiveString) { return s.equalsIgnoreCase((CaseInsensitiveString) o), s); } if (o instanceof String) { return s.equalsIgnoreCase((String) o); } return false; } ... }

이 클래스의 equals 메소드는 일반 문자열과도 호환되도록 하려는 시도를 하고 있다.

CaseInsensitiveString cis = new CaseInsensitiveString("Polish"); String s = "polish";

cis.equals(s)는 true를 반환할 것이다. 하지만 s.equals(cis) 는 false 를 반환한다.
대칭성이 깨지는 것이다.
이 문제를 해결하기 위해서는 String객체와 상호작용하지 않도록 해야한다.

@Override public Boolean equals(Object o) { return o instaceof CaseInsensitiveString && ((CaseInsensitiveString) 0).s.equalsIgnoreCase(s); }


3. 추이성 (Transitivity)
=> A 객체 = B 객체 이고 B 객체 = C 객체이면 A 객체 = C 객체 이여야 한다.
상위 클래스에 없는 새로운 값 컴포넌트(value component)를 하위 클래스에 추가하는 상황을 생각해 보자. 다시 말해 equals가 비교할 새로운 정보를 추가한다.
2차원 공간상의 점(point)을 나타내는 변경 불가능(immutable)클래스를 예제로 보자

public class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object o) { if (!(o instanceof Point)) { return false; } Point p = (Point) o; return p.x == x && p.y == y; } .... }

이 클래스를 상속해서 색상 정보를 추가해 보자.

public class ColorPoint extends Point { private final Color color; public ColorPoint(int x, int y, Color color) { super(x, y); this.color = color; } //대칭성 위반!!!! @Override public boolan equals(Object o) { if(!(o instanceof ColorPoint)) { return false; } return super.equals(o) && ((ColorPoint) o).color == color; } }

이 메서드의 문제는 Point 객체와 ColorPoint 객체를 비교하는 순서를 바꾸면 다른 결과를 반환될 수 있다는 점이다.
Point를 ColorPoint 와 비교하면 생상이 무시되고, 반대로 하면 인자로 전달된 객체의 자료형 때문에 항상 false가 반환된다.

Point p = new Point(1, 2); ColorPoint cp = new ColorPoint(1, 2, Color.RED);

이 상태에서 p.equals(cp)를 호출하면 true가, cp.equals(p)를 수행하면 false가 반환된다.

@Override public boolean equals(Object o) { if(!(o instanceof Point)) } return false; } //o가 Point 객체이면 색상은 비교하지 않음 if (!(o instanceof ColorPoint)) { return o.equals(this); } //o가 ColorPoint이므로 모든 정보를 비교 return super.equals(o) && ((ColorPoint) o).color == color; }

이렇게 하면 대칭성은 보존되지만 추이성은 깨진다.

ColorPoint p1 = new ColorPoint(1, 2, Color.RED); Point p2 = new Point(1, 2); ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);

p1.equals(p2)와 p2.equals(p3)는 true를 반환하지만 p1.equals(p3)는 false를 반환한다.
객체 생성 가능 클래스를 계승하여 새로운 값 컴포넌트를 추가해서 equals 규약을 어기지 않을 방법은 없다.

4. 일관성 (Consistency)
일단 같다고 판정된 객체들은 추후 변경되지 않는 한 계속 같아야 한다.
신뢰성이 보장되지 않는 자원들을 비교하는 equals를 구현하는 것을 삼가라
예를 들어 java.net.URL의 equals메서드는 URL 에 대응되는 호스트의 IP주소를 비교하여 equals의 반환값을 결정한다. 문제는 호스트명을 IP주소로 변환하려면 네트워크에 접속해야 하므로, 언제나 같은 결과를 나온다는 보장이 없다.

5. NULL에 대한 비 동치성
모든 객체는 null 과 동치 관계에 있지 아니한다.

위 규약들을 지키기 위한 지침들을 아래에 서술한다.
1. == 연산자를 사용하여 equqls의 인자가 자기 자신인지 검사한다.
=> 만일 그렇다면 true를 반환해라

2. instanceof 연산자를 사용하여 인자의 자료형이 정확한지 검사하라.
=> 그렇지 않다면 false를 반환해라

3. equals의 인자를 정확한 자료형으로 반환해라
=> 그 앞에 instanceof 를 사용한 검사 코드를 두었으므로, 형 변환은 반드시 성공.

4. "중요" 필드 각각이 인자로 주어진 객체의 해당 필드와 일치하는지 검사한다.
=> 중요 필드가 모두 일치하면 true를 반환한다.

5. equals 메서드 구현을 끝냈다면, 대칭성, 추이성, 일관성의 세 속성이 만족되는지 검토하라
=> 단위 테스트로 검사해라!


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함