3장 : 모든 객체의 공통 메서드

2023. 4. 5. 18:44스터디/이펙티브 자바 스터디

728x90

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

# equals를 재정의 하면 안되는 상황

1. 각 인스턴스가 본질적으로 고유함

2. 인스턴스의 논리적 동치성을 검사할 일이 없음

3. 상위 클래스에서 재정의한 equals가 하위 클래스에서도 딱 들어맞음

4. 클래스가 private,package-private 이고, equals 메서드 호출할 일이 없음

 

# equals를 재정의 해야하는 경우

1. equals가 논리적 통치성을 비교하도록 재정의되지 않았을 경우

2. 객체가 같은지가 아니라 값이 같은지 알고싶을 경우

3. 같은 인스턴스가 둘 이상 만들어지지 않음을 보장하는 경우. ex) enum

 

# equals 메서드 재정의시 따라야하는 일반 규약

1. 반사성 : x.equals(x) == true

2. 대칭성 y.equals(x) == x.equals(y)

3. 추이성: x.equals(y), y.equals(z) 면 z.equals(x)

4. 일관성 : x.equals(y) 반복해서 호출해도 계속 같은 값을 가져야

5. null-아님 : x가 null이 아닐 때 x.equals(null)은 false

 

# equals 메서드 구현 방법 단계

1. == 연산자를 사용해 입력이 자기 자신의 참조인지 확인

2. instanceof 연산자로 입력이 올바른 타입인지 확인

3. 입력을 올바른 타입으로 형변환한다

4. 입력 객체와 자기 자신의 대응되는 핵심 필드들이 모두 일치하는지 하나씩 검사 - 성능 향상을 위해 다른 가능성이 더 크거나 비교비용이 싼 것 우선적으로 비교

 

# equals 재정의시 주의사항

1. hashCOde도 반드시 재정의

2. 별칭은 비교하지 않는게 좋음

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

- hashcode 메서드는 몇 번을 호출해도 일고나되게 항상 같은값을 반환해야

- 두 객체의 hashCode는 똑같은 값을 반환해야 : 논리적으로 같은 객체는 같은 해시코드를 반환해야 - hashHap은 해시코드가 다른 엔트리끼리는 동치성 비교를 시도조차 하지 않음

- equals 가 두 객체를 다르다고 판단해도, hashcode가 다른 값을 반환할 필요는 없음, 허나, 다른 값을 반환해야 해시테이블 성능이 좋아짐

# hashCode 작성 요령

1. int 변수 result 선언 및 초기화

2. 핵심 필드 k 에 대해

2-1. 기본 타입이면 Type.hashCode(k) 수행

2-2. 참조 타입이면 해당 클래스의 hashCode 호출

2-3. null 인 경우 0 사용

3. result = 31 * result + k 하여 모든 k 계산

 

- hash계산 시 equals 비교에 사용되지 않는 필드는 반드시 제외되야

- Object.hash(k1, k2...) 메서드를 호출해도 되나, 성능에 민감하지 않은 상황에서만 사용

- 클래스고 불변이고, 해시코드를 계싼하는 비용이 크다면, 캐싱 방식을 고려

- 성능을 높인다고 핵심 필드를 생략해서는 안 됨.

- hash 반환 규칙을 굳이 문서화할 필요는 없음


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

- 재정의 안하면 [클래스명@16진수_해시코드]로 반환 : 댕쓸데없음

- 간결하면서 사람이 읽기 쉬운 형태의 유익한 정보로 반환

- 당장 내가 호출하지 않더라도 다른 어딘가에서는 쓰일수도

- 해당 객체가 가진 주요 정보를 모두 반환하는게 좋음

- 스스로를 완벽히 설명하는 문자열이여야

- 포멧에 대한 작성자의 의도를 명확히 밝혀야

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

- Cloneable을 구현하는 것만으로는 외부 객체에서 clone 메서드를 호출할 수 없음

- Cloneable은 Object의 protected 메서드인 clone 동작 방식을 결정

 

# clone 메서드 규약

1. x.clone() != x

2. x.clone().getClass() == x.getClass()

3. x.clone().equals(x) 는 일반적으로 참, 허나 필수는 아님

 

- clone()을 구현한 클래스의 하위 클래스에서 super.clone을 호출시 잘못된 클래스의 객체가 만들어짐 --> 하위 클래스의 clone 메서드가 제대로 동작하지 않을 수도

- 모든 필드가 기본 타입이거나 불변 객체를 참조한다면 손볼게 없음 : 불변 클래스는 굳이 clone 메서드를 제공하지 않는게 좋음

- 재정의한 메서드의 반환 타입은 상위 클래스의 메서드가 반환하는 타입의 하위 타입일 수 있음

- clone 메서드는 사실상 생성자와 같은 효과를 냄 즉, clone은 원본 객체에 아무런 해를 끼치지 않는 동시에 복제된 객체의 불변식을 보장해야

- 배열을 복제할 때는 배열의 clone 메서드를 사용하길 권장

- public clone 메서드에서는 throws를 없애야

- 상속용 클래스에서는 Cloneable을 구현해서는 안 됨

- Cloneable을 구현한 스레드 안전 클래스 작성시 clone 메서드 역시 적절히 동기화해야

- Cloneable을 구현하는 모든 클래스는 clone을 재정의 해야, 이때 접근 제한자는 public으로, 반환 타입은 클래스 자신으로 변경, 메서드에서 가장 먼저 super.clone을 호출 후 필요한 필드를 수정

- 복사 생성자와 복사 팩터리가 Cloneable/clone 보다 나을 확률이 높음 : 구현 타입에 얽메이지 않고 복제본 타입을 선택할 수 있기 때문.

- 새로운 인터페이스 생성시 Cloneable을 확장해서는 안 됨.

- 배열만이 clone 메서드 방식이 가장 합당함

아이템 14. Comparable을 구현할지 고려하라 

# CompareTo 규약1. x.compareTo(y) == -y.compareTo(x)2. x.comporeTo(y) > y.compareTo(z) 면 x.compareTo(z) > 03. x.comporeTo(y) ==0,  y.compareTo(z)==0, 면 x.compareTo(z) == 0반사성, 대칭성 , 추이성을 만족해야

 

- Compareable을 구현하지 않는 필드나 표준이 아닌 순서로 비교해야 한다면 Comparator 사용- 관계연산자(<.>) 를 사용하는 거추장스럽고 오류를 유발

 

 

 

728x90

'스터디 > 이펙티브 자바 스터디' 카테고리의 다른 글

7장 : 람다와 스트림  (0) 2023.04.06
6장 : 열거 타입과 애너테이션  (0) 2023.04.06
5장 : 제네릭  (0) 2023.04.06
4장 : 클래스와 인터페이스  (0) 2023.04.06
2장 : 객체 생성과 파괴  (0) 2023.04.04