이펙티브 자바-3장 모든 객체의 공통 메서드

TL;DR

모든 클래스는 이 메서드들을 일반 규약에 맞게 재정의해야 한다.
메서드를 잘못 구현하면 대상 클래스가 이 규약을 준사한다고 가정하는 클래스(HashMap과 HashSet 등)를 오동작하게 만들 수 있다.
이번 장에서는 final이 아닌 Object 메서드들을 언제 어떻게 재정의해야 하는지를 다룬다.


아이템 10. equals는 일반 규약을 지켜 재정의하라

다음에서 열거한 상황 중 하나에 해당한다면 재정의하지 않는 것이 최선이다.

  1. 각 인스턴스가 본질적으로 고유하다.
  2. 인스턴스의 ‘논리적 동치성(logical equality)‘을 검사할 일이 없다.
  3. 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다.
  4. 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없다.

반사성은 단순히 말하면 객체는 자기 자신과 같아야 한다는 뜻이다.
대칭성은 두 객체는 서로에 대한 동치 여부에 똑같이 답해야 한다는 뜻이다.
equals 규약을 어기면 그 객체를 사용하는 다른 객체들이 어떻게 반응할지 알 수 없다.
구체 클래스를 확장해 새로운 값을 추가하면서 equals 규약을 만족시킬 방법은 존재하지 않는다.
equals의 판단에 신뢰할 수 없는 자원이 끼어들게 해서는 안 된다.

양질의 equals 메서드 구현 방법을 단계별로 정리해보자.

  1. == 연산자를 사용해 입력이 자기 자신의 참조인지 확인한다.
  2. instanceof 연산자로 입력이 올바른 타입인지 확인한다.
  3. 입력을 올바른 타입으로 형변환한다.
  4. 입력 객체와 자기 자신이 대응되는 ‘핵심‘필드들이 모두 일치하는지 하나씩 검사한다.

equals를 다 구현했다면 세 가지만 자문해보자.

  1. 대칭적인가? 추이성이 있는가? 일관적인가?
  2. equals를 재정의할 땐 hashCodde도 반드시 재정의하자
  3. 너무 복잡하게 해결하려 들지 말자.
    꼭 필요한 경우가 아니면 equals를 재정의하지 말자.
    많은 경우에 Object의 equals가 원하는 비교를 정확히 수행해준다.
    재정의해야 할 때는 그 클래스의 핵심 필드 모두를 빠짐없이, 다섯 규약을 확실히 지켜가며 비교해야 한다.

아이템 11. equals를 재정의하려거든 hashCode도 재정의하라

equals를 재정의한 클래스 모두에게 hashCode도 재정의해야 한다.
논리적으로 같은 객체는 같은 해시코드를 반환해야 한다.
성능을 높인답시고 해시코드를 계산할 때 핵심 필드를 생략해서는 안 된다.
hashCode가 반환하는 값의 생성 규칙을 API 사용자에게 자세히 공표하지 말자.
그래야 클라이언트가 이 값에 의지하지 않게 되고, 추후에 계산 방식을 바꿀 수도 있다.


아이템 12. toString을 항상 재정의하라

toString을 잘 구현한 클래스는 사용하기에 훨씬 즐겁고, 그 클래스를 사용한 시스템은 디버깅하기 쉽다.
실전에서 toString은 그 객체가 가진 주요 정보 모두를 반환하는 게 좋다.
포맷을 명시하든 아니든 여러분의 의도는 명확히 밝혀야 한다.
toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하자.
모든 구체 클래스에서 Object의 toString를 재정의하자.
toString을 재정의한 클래스는 사용하기도 즐겁고 그 클래스를 사용한 시스템을 디버깅하기 쉽게 해준다.
toString은 해당 객체에 관한 명확하고 유용한 정보를 읽기 좋은 형태로 반환해야 한다.


아이템 13. clone 재정의는 주의해서 진행하라

실무에서 cloneable을 구현한 클래스는 clone 메서드를 public으로 제공하며, 사용자는 당연히 복제가 제대로 이뤄지리라 기대한다.
cloneable 아키텍처는 ‘가변 객체를 참조하는 필드는 final로 선언하라’는 일반 용법과 충돌한다.
publicclone 메서드에서는 throws 절을 없애야 한다.
복사 생성자와 복사 팩터리라는 더 나은 객체 복사 방식을 제공할 수 있다.