-
[EffectiveKotlin] equals, hashcode 규약과 data class, jpa언어/Kotlin 2022. 6. 1. 23:50반응형
먼저 jdk의 equals, hashcode 함수를 확인해보자. 모든 동등성을 주소값으로 처리한다.
class Object { . . @IntrinsicCandidate public native int hashCode(); . . public boolean equals(Object obj) { return (this == obj); } . . }
- equals는 객체의 주소값으로 같은지 다른지 판단하고 있다.
- Kotlin으로 치면 ===
- hashCode는 메모리에서 객체의 Hash 주소값을 반환한다.
- native 키워드는 함수를 java에서 직접 구현하지 않고, 외부의 함수를 호출할 수 있다.
- 개발 규약
- hashCode 규약
- 어떤 객체의 hashCode는 여러 번 호출해도 항상 같은 결과가 나와야 한다.
- equals의 결과로 두 객체가 같다고 나오면 hashCode의 결과도 같야 한다.
- equals 규약
- 반사적 : x가 Null이 아닌 값이라면 x.equals(x)는 true이다.
- 대칭적 : x와 y가 null이 아닌 값이라면, x.equals(y)는 y.equals(x)와 같다.
- 연속적 : x, y, z가 null이 아닌 값이고 x.equals(y)와 y.equals(z)가 ture라면, x.equals(z)도 true이다.
- 일관적 : x와 y가 null이 아니라면 x.equals(y)는 여러 번 실행하더라도 항상 같은 결과를 낸다.
- 널 관련된 동작 : x가 null이 아닌 값이라면, x.equals(null)은 항상 false를 리턴해야 한다.
- hashCode를 override하면 equals도 override 한다.
- 왜 override 하나?
- Kotlin의 문법과 객체의 사용법을 일관성있게 사용하기 위함이다.
- List의 contains함수는 equals를 이용하여 동일한 객체를 찾는다. 그러므로 아래와 같은 코드는 개발자의 의도와는 다르게 동작한다.
class Test( val first: String, val second: String, val third: String, ) val testList = listOf(Test("a", "b", "c"), Test("d", "e", "f")) // Test("a", "b", "c")가 있는지 찾고싶다. testList.contains(Test("a", "b", "c")) // false
- hashCode는 HashMap에서 사용되는 HashTable에서 사용된다. 같은 값을 return할 경우 성능에 영향을 미친다.
- 사용
1. String의 equals와 hashCode : 사용자 정의 equals와 hashCode
class String { . . // StringUTF16의hashCode public static int hashCode(byte[] value) { int h = 0; int length = value.length >> 1; for (int i = 0; i < length; i++) { h = 31 * h + getChar(value, i); } return h; } . . // StringLatin1의 equals public static boolean equals(byte[] value, byte[] other) { if (value.length == other.length) { for (int i = 0; i < value.length; i++) { if (value[i] != other[i]) { return false; } } return true; } return false; } . . }
- 우리가 자주 사용하는 String 클래스는 hashCode와 equals를 override하여 사용하기 때문에 아래와 같은 equals(==)사용이 가능하다.
val text1 = "a" val text2 = "a" val text3 = String("a".toByteArray()) println(text1 == text2) // true println(text1 == text3) // true
2. 먼저 data class를 고려하자.
- data class는 컴파일 시점에 equals(), hashCode(), copy(), toString() 함수를 자동으로 생성한다.
- data class의 equals는 생성자에 정의된 모든 값이 동일한지 아닌지를 체크하기 때문에 일부 값만 비교하고 싶은 경우 equals를 새로 override해야 한다.
3. JPA Entity 객체
- data class는 사용하지 말자.
- PK를 활용하여 equals를 구현하자.
- PK가 null인 객체(영속성 컨텍스트에 의해 관리되지 않는 Entity)는 어떻게 equals를 수행할 것인가?
- 정답은 없다. 상황에 맞게 구현하자.
- 결론
- override 전 date class를 먼저 고려하자.
- hashCode override 시 Obejects.hash함수를 먼저 고려하자.
- 규약을 지키면서, equals와 hashCode를 override하자
참고 :
https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Object.java
https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/String.java
반응형'언어 > Kotlin' 카테고리의 다른 글
[Apache PDFBox] 코틀린 임시파일 및 내용 생성 (1) 2024.06.03 [properties, env] 자바에서 시스템 환경변수 읽어오기 (0) 2024.04.20 [EffectiveKotlin] 상속보다는 컴포지션을 사용하라 (0) 2022.06.01 [Kotlin in Action, Effective Kotlin] 제네릭과 변성 variance (0) 2022.05.29 [Kotlin] - List의 합집합, 차집합, 교집합 (0) 2022.05.08 - equals는 객체의 주소값으로 같은지 다른지 판단하고 있다.