250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- vue.js
- 스프링부트와AWS로혼자구현하는웹서비스
- 이팩티브 자바
- 자바
- CleanCode
- 혼공SQL
- DDD
- AWS
- 도메인 주도 개발 시작하기
- 인프런백기선
- 기술면접
- 알고리즘
- jpa
- 이펙티브자바
- 인덱스
- 자바스터디
- SQL쿡북
- 이펙티브 자바
- 알고리즘분석
- AWS RDS
- 자료구조
- MariaDB
- java
- 자바예외
- react
- 인프런김영한
- mysql
- aop
- 클린코드
- 네트워크
Archives
- Today
- Total
기록이 힘이다.
[이펙티브 자바] 10. equals는 일반 규약을 지켜 재정의하라 본문
728x90
핵심 정리: equals를 재정의 하지 않는 것이 최선
- 다음의 경우에 해당된다면 equals를 재정의 할 필요가 없다.
- 각 인스턴스가 본질적으로 고유하다. ex)enum
- 인스턴스의 '논리적 동치성'을 검사할 필요가 없다.
- 상위 클래스에서 재정의한 equals가 하위 클래스에도 적절하다.
- 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없다.
핵심 정리: equals 규약
- 반사성: A.equals(A) == true
- 대칭성: A.equals(B) == B.equals(A)
- CaseInsensitiveString
package me.whiteship.chapter02.item10;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
// 코드 10-1 잘못된 코드 - 대칭성 위배! (54-55쪽)
public final class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s) {
this.s = Objects.requireNonNull(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;
}
// 문제 시연 (55쪽)
public static void main(String[] args) {
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
// CaseInsensitiveString cis2 = new CaseInsensitiveString("polish");
String polish = "polish";
System.out.println(cis.equals(polish));
// System.out.println(cis2.equals(cis));
List<CaseInsensitiveString> list = new ArrayList<>();
list.add(cis);
System.out.println(list.contains(polish));
}
// 수정한 equals 메서드 (56쪽)
// @Override public boolean equals(Object o) {
// return o instanceof CaseInsensitiveString &&
// ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
// }
}
- 추이성: A.equals(B) && B.equals(C), A.equals(C)
- Point, ColorPoint(inherit), CounterPointer, ColorPoint(comp)
package me.whiteship.chapter02.item10.inheritance;
import me.whiteship.chapter02.item10.Color;
import me.whiteship.chapter02.item10.Point;
// Point에 값 컴포넌트(color)를 추가 (56쪽)
public class ColorPoint extends Point {
private final Color color;
public ColorPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
// 코드 10-2 잘못된 코드 - 대칭성 위배! (57쪽)
// @Override public boolean equals(Object o) {
// if (!(o instanceof ColorPoint))
// return false;
// return super.equals(o) && ((ColorPoint) o).color == color;
// }
// // 코드 10-3 잘못된 코드 - 추이성 위배! (57쪽)
@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;
}
public static void main(String[] args) {
// 첫 번째 equals 메서드(코드 10-2)는 대칭성을 위배한다. (57쪽)
// Point p = new Point(1, 2);
// ColorPoint cp = new ColorPoint(1, 2, Color.RED);
// System.out.println(p.equals(cp) + " " + cp.equals(p));
// 두 번째 equals 메서드(코드 10-3)는 추이성을 위배한다. (57쪽)
ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
System.out.printf("%s %s %s%n",
p1.equals(p2), p2.equals(p3), p1.equals(p3));
}
}
새로운 필드를 추가하면 equals 규약을 만족시킬 방법은 존재하지 않는다.
package me.whiteship.chapter02.item10.inheritance;
import me.whiteship.chapter02.item10.Color;
import me.whiteship.chapter02.item10.Point;
import java.util.Set;
// CounterPoint를 Point로 사용하는 테스트 프로그램
public class CounterPointTest {
// 단위 원 안의 모든 점을 포함하도록 unitCircle을 초기화한다. (58쪽)
private static final Set<Point> unitCircle = Set.of(
new Point( 1, 0), new Point( 0, 1),
new Point(-1, 0), new Point( 0, -1));
public static boolean onUnitCircle(Point p) {
return unitCircle.contains(p);
}
public static void main(String[] args) {
Point p1 = new Point(1, 0);
Point p2 = new CounterPoint(1, 0);
// true를 출력한다.
System.out.println(onUnitCircle(p1));
// true를 출력해야 하지만, Point의 equals가 getClass를 사용해 작성되었다면 그렇지 않다.
System.out.println(onUnitCircle(p2));
}
}
package me.whiteship.chapter02.item10.composition;
import me.whiteship.chapter02.item10.Color;
import me.whiteship.chapter02.item10.Point;
import java.util.Objects;
// 코드 10-5 equals 규약을 지키면서 값 추가하기 (60쪽)
public class ColorPoint {
private final Point point;
private final Color color;
public ColorPoint(int x, int y, Color color) {
point = new Point(x, y);
this.color = Objects.requireNonNull(color);
}
/**
* 이 ColorPoint의 Point 뷰를 반환한다.
*/
public Point asPoint() {
return point;
}
@Override public boolean equals(Object o) {
if (!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint) o;
return cp.point.equals(point) && cp.color.equals(color);
}
@Override public int hashCode() {
return 31 * point.hashCode() + color.hashCode();
}
}
- 일관성: A.equals(B) == A.equals(B)
- null-아님: A.equals(null) == false
package me.whiteship.chapter02.item10;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Timestamp;
import java.util.Date;
public class EqualsInJava extends Object {
public static void main(String[] args) throws MalformedURLException {
long time = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(time);
Date date = new Date(time);
// 대칭성 위배! P60
System.out.println(date.equals(timestamp));
System.out.println(timestamp.equals(date));
// 일관성 위배 가능성 있음. P61
URL google1 = new URL("https", "about.google", "/products/");
URL google2 = new URL("https", "about.google", "/products/");
System.out.println(google1.equals(google2));
}
}
핵심 정리: equals 구현 방법
- == 연산자를 사용해 자기 자신의 참조인지 확인한다.
- instanceof 연산자로 올바른 타입인지 확인한다.
- 입력된 값을 올바른 타입으로 형변환 한다.
- 입력 객체와 자기 자신의 대응되는 핵심 필드가 일치하는지 확인한다.
- 구글의 AutoValue 또는 Lombok을 사용한다.
- IDE의 코드 생성 기능을 사용한다.
부동소수점은 float이나 double의 compare()을 통해 비교 아닌 것은 equals를 통해 비교하면 된다.
핵심정리: 주의 사항
-equals를 재정의 할 때 hashCode도 반드시 재정의하자.(아이템11)
너무 복잡하게 해결하지 말자.
-Object가 아닌 타입의 매개변수를 받는 equals 메서드는 선언하지 말자.
'JAVA' 카테고리의 다른 글
[이펙티브 자바] 12. toString을 항상 재정의하라 (0) | 2023.03.19 |
---|---|
[이펙티브 자바] 11. equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2023.03.17 |
[이팩티브 자바] 아이템 9 try-finally 보다 try-with-resouces를 사용하라. (0) | 2023.03.07 |
[이팩티브 자바]아이템 8. 완벽 공략 Finalizer/ AutoCloseable (0) | 2023.03.07 |
아이템6 불필요한 객체 생성을 피하라 (0) | 2023.01.27 |