본문 바로가기

프로그래밍/자바(java)

[이펙티브 자바] 습관적으로 사용하는 Object 메소드

equals의 일반 규약을 지켜 재정의하라

 

 

String와 같은 class가 같은지 확인하는 메소드입니다.

 

 

class에서 equals와 hashcode를 오버라이딩해본 사진이다.

hashcode도 오버라이딩하는 이유는 논리적으로 같은 객체라면 같은 hashcode를 반환하기 위해서이다.

 

 

Speaker의 해시 코드를 재정의 해주지 않으면, 값이 두개가 들어가게 되어 Map의 값이 2개는 일이 벌어지게 된다.

hashCode를 재정의할때, Objects.hasCode로 재정의할 수 있다.

하지만, 속도가 상대적으로 더 느리다. 

 

 

해시코드를 지연 초기화(lazy initialization) 하는 방법

 

지연초기화를 통해 캐쉬처리하면 유용한데 스레드 안전성까지 고려해야한다.

 

 

 

 

실제 업무에서는 lombok을 사용하여 @EqaulsAndHashCode를 사용하게 되면 static 이나 메소드를 제외한 값의 해쉬코드를 알아서 정의해준다.

 

 

 

equals를 재정의해야하는 경우는 다음과 같다.

 

1. 객체의 동일성이 아닌 논리적동일성 즉, 주소값으로 체크가 아니라 안에 내용의 값을 체크형식을 경우 equals을 재정의한다.

2. 상위 클래스의 equals가 하위 클래스의 요구를 충족하지 못하였을떄 재정의한다.

 

Java의 Object 클래스 명세에서 기술하고 있는 규약이 있다.

 

  • 반사성

null이 아닌 참조 x가 있을 때, x.equlas(x)는 true를 반환한다.

  • 대칭성

null이 아닌 참조 x와 y가 있을 때, x.equlas(y)는 y,equals(x)가 true일때만 true를 반환한다.

  • 추이성

null이 아닌 참조 x,y,z가 있을 때, x.equals(y)가 참이고 y,equals(z)가 차이면, x.equlas(z)도 참이어야 한다.

  • 일관성

null이 아닌 참조 x와 y가 있을 때 equals를 통해 비교되는 정보에 변화가 없다면, 몇번 반복하더라도 같은 결과를 유지해야한다.

 

 

Equals를 override하지 않는것이 최선일떄

 

1. 각 인스턴스가 고유한 경우, 값안에 객체가 있을떄

2. 값이 같음을 증명하지 않을 경우

3. 상위 클래스의 equals만으로 하위 클래스를 사용하기 무리 없을떄, 즉, 하위클래스가 메소드만 있을경우

4. private class로 만든 경우 equals를 사용할 일이 없을 떄

 

 

 

toString을 항상 override 하라

 

toString의 defaultValue는 className@16진수 hashCode를 반환한다.

toString의 일반 규약은 간결하고 사람이 읽기 쉬운 형태의 유익한 정보이다.

이펙티브 자바에서는 toString은 항상 Override하여 재정의하는것을 추천하고 있다.

 

 

 

 

lombok을 이용하여 @ToString을 사용하게 되면 아래와 같이 class + 필드이름 + 값 순서로 나오게 된다.

 

 

 

또한 @ToString에서 불필요한 필드일경우 Exclude를 사용하여 제외할수 도 있다.

 

 

clone 재정의는 주의해서 사용하라

 

 

배열을 다른 배열로 값을 넣게 되면 Shallow Copy라고 하며, clone을 이용하여 Deep copy라고 한다.

 

 

주의사항

 

 

a 가 변경되면 b도 변경이 되는 문제점이 있다.

a[0] 와 b[0]는 같은 주소를 바라보고 있기 떄문이다.

Clonable을 생성자를 생성하지 않고 그대로 값을 반환하기 때문에 primitive가 아니면 값이 주소값을 그대로 반환하여 영향을 주고 있다.

 

객체의 복사본을 생성해 반환한다. 복사의 정확한 뜻은 클래스에 따라 다를 수 있다.

만약에 상위 클래스가 존재할 경우 super.clone()을 사용할 경우 상위클래스 값을 클론하게 되어 값이 달라 질 수 있으므로 주의를 해야한다.

 

x.clone() != x. // 참
x.clone().getClass() == x.getClass() // 참
x.clone().equlas(x) // 일반적으로 참

 

그러면 어떻게 복사를 해야 할까?

 

1. conversion Constructor

 

 

생성자로 새로 생성해서 복사를 할 수 있다.

 

 

2. conversion Factory

 

 

 

static 메소드를 만들어 새로운 객체를 반환하면 된다.

 

 

Comparable을 구현할지 고려하라

 

객체와 주어진 객체의 순서를 비교한다.

 

이 객체가 주어진 객체보다 작으면 음의 정수, 같으면 0, 크면 양의 정수를 반환한다.

비교할 수 없을 땐 ClassCastException

 

 

 

자바 7이후에는 comparTo가 Integer내에 메소드가 추가되었다.

 

 

실습해보기

 

 

 

 

Person이라는 객체에서 나이순 -> 키 -> 이름으로 정렬을 해보는 실습을 해보자면

 

1. compareTo 안에서 메소드 별로 compare 메소드를 사용하여 비교를 한다.

 

 

2. Java 8에서 추가된 compator의 thenComparing을 사용하여 추가한다.