class Person(val name: String, val age: Int)
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a.equals(b))
}
위 코드의 출력은 무엇입니까?
이름과 나이가 같으니 사실대로 나와야 한다.
그러나 출력이 잘못되었습니다.
왜?
1. 같음 ()
equals라고 하는 HashCode 및 toString은 모든 Kotlin 개체의 최상위 클래스인 Any 클래스의 메서드입니다.
Kotlin에서 equal은 ==라고도 합니다.
equals 메서드는 두 개체가 같은지 비교하는 데 사용됩니다.
위의 코드에서 a와 b는 같은 이름과 나이로 선언되었지만 다르게 나옵니다.
그 이유는 a와 b가 출력될 때 알 수 있습니다.
class Person(val name: String, val age: Int)
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a)
println(b)
}
출력 결과에서 알 수 있듯이 a와 b는 클래스 개체이지만 출력 결과는 클래스의 주소 값입니다.
그러나 주소 값과 나발이고 원하는 결과는 “a와 b가 같다”입니다.
우리는 컴퓨터가 아니라 인간이기 때문에 앞으로 스크롤할 때 동일하게 보이는 두 개체가 동일해야 합니다.
따라서 Any 클래스의 equals 함수를 재정의할 수 있습니다.
class Person(val name: String, val age: Int){
override fun equals(other: Any?): Boolean {
if (other !
is Person) return false
return this.name == other.name && this.age == other.age
}
}
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a.equals(b))
}
위와 같음을 재정의한 후 동일한 결과의 출력이 참 값이 됩니다.
이겼다
그는 행복하게 프로그래밍하고 컴퓨터를 비웃으며 인간이 이겼다고 주장하면서 치명적인 결함을 발견했습니다.
class Person(val name: String, val age: Int){
override fun equals(other: Any?): Boolean {
if (other !
is Person) return false
return this.name == other.name && this.age == other.age
}
}
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a.equals(b)) // true 내가 이김
val hashSet = hashSetOf(a)
println(hashSet.contains(b))
}
중복되지 않는 요소를 저장하고 있는 HashSet에 a를 삽입한 후 b가 같은 값인지 확인한 결과
잘못 나옴 예상치 못한 결과입니다.
2. 해시코드()
hashCode()는 객체의 해시 코드를 반환하는 메서드입니다.
해시 코드는 개체를 식별하는 정수 값이며 equals() 메서드에서 사용됩니다.
hashCode() 메서드가 구현되지 않은 경우 객체의 메모리 주소를 기반으로 기본적으로 해시 코드가 생성됩니다.
즉, 위의 코드에서 hashSet은 객체 a의 해시 코드 값을 저장하고 contains()가 호출될 때 객체의 해시 코드를 비교하여 false가 됩니다.
간단히 말해서 위에서 Person@67 b64 c45와 Person@4411 d970을 비교하고 있습니다.
그래서 결국 잘못된 것으로 판명됩니다.
덮어써야 하는거 아닌가? 한편으로는 인간의 승리가 아닌가?
컴퓨터는 생각보다 훨씬 간단합니다.
class Person(val name: String, val age: Int){
override fun equals(other: Any?): Boolean {
if (other !
is Person) return false
return this.name == other.name && this.age == other.age
}
override fun hashCode(): Int {
var result = name.hashCode()
result = 31 * result + age
return result
}
}
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a.equals(b)) // true 내가 이김
val hashSet = hashSetOf(a)
println(hashSet.contains(b))
}
인간의 승리입니다.
다시 한 번 즐겁게 프로그래밍을 하던 중, 조금 답답한 장면이 나왔다.
class Person(val name: String, val age: Int){
override fun equals(other: Any?): Boolean {
if (other !
is Person) return false
return this.name == other.name && this.age == other.age
}
override fun hashCode(): Int {
var result = name.hashCode()
result = 31 * result + age
return result
}
}
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a.equals(b)) // true 내가 이김
val hashSet = hashSetOf(a)
println(hashSet.contains(b)) // true 또 이김 컴퓨터 브론즈인 듯
println("나의 이름과 나이는 ${a}야. 너의 이름과 나이는 뭐야?")
println("안녕? ${a.name}? 나의 이름과 나이는 ${b}야. 만나서 반가워!
")
}
위와 같이 a.name을 원하는 이름으로 부르지만 여전히 a와 b의 주소 값은 호출된다.
제 이름은 개똥이고 12살인데 이름과 나이가 Person@51007661이 되었습니다.
그것은 인공 지능 행위와 같습니다.
3. toString()
toString() 메서드는 객체의 문자열 표현을 반환합니다.
그러나 a와 b는 이름과 나이 정보를 담고 있는 객체이고 toString()을 호출하면 주소 값만 반환된다.
이것도 재정의하면 어떨까요?
class Person(val name: String, val age: Int) {
override fun equals(other: Any?): Boolean {
if (other !
is Person) return false
return this.name == other.name && this.age == other.age
}
override fun hashCode(): Int {
var result = name.hashCode()
result = 31 * result + age
return result
}
override fun toString(): String {
return "Person(name=$name, age=$age)"
}
}
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a.equals(b)) // true 내가 이김
val hashSet = hashSetOf(a)
println(hashSet.contains(b)) // true 또 이김 컴퓨터 브론즈인 듯
println("나의 이름과 나이는 ${a}야. 너의 이름과 나이는 뭐야?")
println("안녕? ${a.name}? 나의 이름과 나이는 ${b}야. 만나서 반가워!
")
}
원하는 결과가 나왔다!
!
● 데이터 클래스
출력도 너무 간편해서 다음에는 어떤 인코딩에도 사용할 수 있을 것 같아요!
앞으로 클래스를 만들 때 우리가 원하는 값을 반환할 수 있도록 재정의하면서 사용할 것입니다!
!
!
유명인이 만든 데이터 클래스라고 생각했는데 잘 모르겠습니다.
위의 코드를 데이터 클래스로 변환하면
data class Person(val name: String, val age: Int)
fun main() {
val a = Person("개똥이", 12)
val b = Person("개똥이", 12)
println(a.equals(b))
val hashSet = hashSetOf(a)
println(hashSet.contains(b))
println("나의 이름과 나이는 ${a}야. 너의 이름과 나이는 뭐야?")
println("안녕? ${a.name}? 나의 이름과 나이는 ${b}야. 만나서 반가워!
")
}
위와 같이 출력됩니다.
잘되고 있어요.
그렇다면 데이터 클래스를 사용하지 않는 이유는 무엇입니까?
데이터 클래스는 데이터를 저장할 클래스를 생성할 때 유용한 기능을 제공합니다.
그러나 모든 클래스가 데이터를 저장하거나 데이터 클래스에서 제공하는 기능만 사용하는 것은 아닙니다.
결정적으로 데이터 클래스는 다른 클래스에서 상속할 수 없습니다.
따라서 데이터 클래스는 상속을 먹는 코딩 세계에서 클래스를 대체할 수 없습니다.