-
Effective Java - 3장. 모든 객체의 공통 메서드(2/2)Computer - Java 2022. 12. 24. 20:36
item 10. equals는 일반 규약을 지켜 재정의하라
item 11. equals를 재정의하려거든 hashCode도 재정의하라
item 12. toString을 항상 재정의하라
item 13. clone 재정의는 주의해서 진행하라
item 14. Comparable을 구현할지 고려하라
12~14는 10~11에 비해서 상대적으로 쉬운 개념?인거 같다
item 12. toString을 항상 재정의하라
- Object.toString : “(클래스명)@(해쉬코드)” 만을 반환 ==> 필요 시 재정의!
toString을 잘 구현한 클래스는 사용하기에 훨씬 즐겁고, 그 클래스를 사용한 시스템은 디버깅하기 쉽다
ex. PhoneNumber 클래스를 만들었다면,
System.out.println(phoneNumber + “에 연결할 수 없습니다”) 를 직관적으로 적을 수 있다.
<주요한 유의점>
- 그 객체가 가진 주요 정보들을 모두 반환하는 것이 좋다.
- 반환값의 포맷을 문서화할지 정해야 한다 - 포맷을 명시하면 그 객체는 표준적이고, 명확하고, 사람이 읽을 수 있게 됨
- 포맷을 명시하던 하지 않던 그 의도는 명확히 밝혀야 함 (예시로 주석 작성을 어떻게 해야하는지 나와있다)
- 반드시 toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하자(안그러면 파싱해야함…)
- item10에서 말한 AutoValue 프레임워크 또한 toString을 잘 설명해 주나, 클래스의 ‘의미’를 파악하진 못한다
(ex. 전화번호와 같은 경우 표준 체계를 따라야 한다 - 123-4567-8901)
item 13. clone 재정의는 주의해서 진행하라
Object.clone의 경우 protected이며, native하며(java코드로 짜져 있지 않다 - JNI), Override하지 않고 그대로 사용 시 CloneNotSupportedException을 발생시킨다.
따라서 이를 사용하기 위해서 implements Cloneable을 해주며, super.clone()을 한 결과를 강제 형 변환시켜 return해주면 된다.
이 때 반드시 try-catch문을 써야 하는데, Object에 throws CloneNotSupportedException(checked exception)가 명시되어 있기 때문이다
자세한건 여기 잘 나와 있더라 - https://developer-youngjun.tistory.com/20
하지만 이 때 clone()는 얕은 복사를 하기 때문에, primitive형이 아닌 객체형은 주소만 복사한다.
재귀적으로 이들 객체를 clone()으로 대입하면 되지 않는가 싶지만, Cloneable 아키텍처는 ‘가변 객체를 참조하는 필드는 final로 선언하라’라는 일반 용법과 충돌한다.
일단 그래서 final을 제외하고, 배열/linked list와 같은 여러 용례에서 적절히 재귀를 쓰던 뭘 하던(...) 잘 복제해주자.
마지막으로 Object.clone()은 멀티스레드를 고려하지 않았기에 반드시 동기화를 해 주어야 한다.
조금 장황하게 써져 있지만, 요약하자면
- 굳이 복사 생성자와 복사 팩토리를 쓰면 될 것을 clone()을 사용하는 것은 좋은 선택지는 아니다.
- 쓸 거라면(책에서 배열 등의 clone, 성능 면에 이점이 있다고는 했다), Object.clone()은 얕은 복사를 한다는 점, 동기화를 해 주어야 한다는 점을 명심하자.
정도일 것 같다.
item 14. Comparable을 구현할지 고민하라
<기본 Comparable 소개>
구현 어떻게 : 클래스 implements Comparable<클래스>
구현할 때 이점 : Arrays.sort, TreeSet, TreeMap 등 여러 기능을 쓸 수 있다(이 친구들이 비교연산을 사용한다)
a.compareTo(b)를 구현할 때
a>b : 양수, a=b : 0, a<b : 음수
비교 불가 : throw ClassCastException
<일반적인 규약>
a.compareTo(b)와 b.compareTo(a)의 부호는 반대. (대칭성)
a>b, b>c라면 a>c에 해당하는 결과가 나와야 함 (추이성)
a=b라면 a>c -> b>c, a=c -> b=c, a<c -> b<c가 만족해야 함 (반사성?)
(필수는 아니지만) compareTo가 0이면 equals가 true여야 한다.
equals(item 10)와 마찬가지로 자식 클래스를 만들었을 때 LSP가 지켜지지 않을 수 있다 - 확장 대신 독립된 클래스를 만들자!
- ex. 분명히 parent형에서는 a=b였는데 child형에서는 compare 기준이 추가되어 a<b가 될 수 있다
<구현 시>
primitive라고 할지라도 <, >를 쓰는 것은 권하지 않는다 - (Wrapper).compare가 더 정확, 오류도 안 난다
핵심 필드부터 비교하자(대소 빨리 구분 시키게)
Comparator 인터페이스는 이를 굉장히 이쁘게 만들 수 있다
Comparator<T> c = comparingInt(T a -> a.a).thenCompairingInt(a->a.b).thenComparingInt(a->a.c);
이후 c.compare(T a, T b) 요런 느낌
값의 차로 compareTo 함수는 구현하지 말자 - 정수 오버플로 or 부동소수점 계산 방식 때문에 오류 가능
ex) int형에서 2147483647 - (-2147483647)은 음수로 나온다
'Computer - Java' 카테고리의 다른 글
JPA 객체 사용 시 instanceof 는 주의해서 사용하자 (0) 2024.06.30 Effective Java - 3장. 모든 객체의 공통 메서드(1/2) (0) 2022.12.24 Effective Java - 2장. 생성과 파괴(3/3) (0) 2022.12.23 Effective Java - 2장. 생성과 파괴(2/3) (0) 2022.12.23 Effective Java - 2장. 생성과 파괴(1/3) (0) 2022.12.23