Scala CH30. 객체의 동일성
아래의 글은 마틴 오더스키,렉스 스푼,빌 베너스 공저 / 오현석,이동욱,반영록 공역, 『Programming in Scala 3/e』,에이콘출판사(2017), CH01의 내용을 기반으로 작성하였습니다.
1. 스칼라에서의 동일성
스칼라와 자바는 동일성의 정의가 다름, == 연산자는 값 타입에 대해서는 자연스러운 등호, 참조 타입의 경우에는 동일한 객체인지, equals 메소드는 참조 타입에 대한 표준 동일성 검사를 제공하는 사용자 정의 메소드
스칼라에사는 값 타입은 == 는 자바와 동일, 객체의 경우 == 는 자바의 equals와 동일 (동일 겍채는 x eq y), 새로운 타입에 대해 equals를 재정의하면 == 의 의미를 재정의 가능
오버라이드 하지 않은 경우는 equals는 자바의 ==와 마찬가지로 객체 동일성 사용
2. 동일성 비교 메소드 작성
equals 구현시 일관성이 없는 동작을 야기할 수 있는 네가지 일반적인 함정
- equals 선언 시 잘못된 시그니처를 사용하는 경우 : equals(other: Any) : Boolean
- equals 를 변경하면서 hashCode는 그대로 놔둔 경우 :
- 만약 equals 메소드로 따졌을 때 두 객체가 같다면, hashCode를 각 객체에 호출한 결과도 같은 정수 값을 만들어내야만 한다
- equals 를 변경가능한 필드의 값을 기준으로 정의한 경우
- equals 를 동치 관계로 정의하지 않은 경우
- 반사성 : reflexive : 널이 아닌 값 x에 대해 x.equals(x) 는 true를 반환해야한다.
- 대칭성 : symmetric : 널이 아닌 값 x, y 에 대해 x.equals(y)가 true이면, y.equals(x) 도 true
- 추이성 : transitive : 널이 아닌 값 x, y, z 에 대해서 x.equals(y)가 true이고 y.equals(z) 도 true 이면 x.equals(z) 도 true를 반환
- 일관성 : consistent : 널이 아닌 값 x, y에 대해 x.equals(y)를 여러 번 호출해도, x, y 객체에 있는 정보가 변경되지 않는 이상 계속 true, false 중 한 값을 일관되게 반환
canEqual
LSP 위배, 에 대한 고민
3. 파라미터화한 타입의 동일성 정의
스칼라는 타입 소거 모델을 채택했고, 타입 파라미터는 실행 시점에 존재하지 않는다.
와일드 카드 타입의 축약표현 : 알려지지 않은 부분이 안에 있는 타입 : Branch[_] : 패턴 매치와 메소드 호출의 타입 파라미터에 있는 밑줄은 서로 다르지만 의미는 같다, 즉 밑줄은 알려지지 않은 것을 표시
class Branch[T] { val elem: T, val left: Tree[T], val right: Tree[T] } extends Tree[T] { override def equals(other: Any) = other match { case that: Branch[_] => (that canEqual this) && this.elem == that.elem && this.left == that.left && this.right == that.right case _ => false } def canEqual(other: Any) = other.isInstanceOf[Branch[_]] override def hashCode: Int = (elem, left, right).## } |
4. equals와 hashCode 요리법