Kotlin 데이터 클래스

데이터 클래스 (data class)

데이터 클래스(Data Class)는 데이터 저장을 위한 클래스이다. 데이터 클래스는 class 키워드 앞에 data를 붙여 선언한다. 데이터 클래스로 선언되면, toString(), hashCode(), equals(), copy() 함수를 자동으로 생성해 주며, 일반 클래스와 거의 동일하게 사용된다.

class Foo1(var name: String)        // 일반 클래스 
data class Foo2(var name: String)   // 데이터 클래스

fun main() {
    var a1 = Foo1("devkuma")
    println(a1)              // Foo1@2280cdac

    var a2 = Foo2("devkuma")
    println(a2)              // Foo2(name=devkuma)

    var a3 = a2.copy()
    println(a3)              // Foo2(name=devkuma)
}

데이터 클래스(Data class)의 특징

  • 상속 받을 수 없다.
  • 생성자 프로퍼티는 val 또는 var으로 생성자 프로퍼티를 선언해야 한다.
  • 생성자에는 1개 이상의 프로퍼티가 선언되어야 한다.
  • abstract, open, sealed, inner를 붙일 수 없다.
  • toString(), hashCode(), equals(), copy()에 Override 구현 시 구현 함수를 사용한다.

자동 생성된 함수

아래 예제들은 아래와 같이 일반 클래스와 데이터 클래스를 생성해서 진행해 보도록 하겠다.

일반 클래스

class PersonGeneral(var name: String, val age: Int)

데이터 클래스

data class PersonData(var name: String, val age: Int)

toString()

toString() 함수는 생성자에 정의된 프로퍼티의 값을 반환하게 된다.

fun main() {
    var personGeneral = PersonGeneral("devkuma", 21)
    var personData = PersonData("devkuma", 21)

    println(personGeneral)
    println(personData)
}

Output:

basic.clazz.data.PersonGeneral@548c4f57
PersonData(name=devkuma, age=21)
  • 일반 클래스의 toString()에서는 객체의 정보가 반환되었다.
  • 데이터 클래스의 toString()에서는 프로퍼티와 값이 반환하고 있다.

hashCode()

hashCode() 함수는 class 객체이면 다른 값을 반환하지만, data class인 경우에는 같은 값을 반환한다.

아래 예제에서는 일반 클래스와 데이터 클래스를 각각 2개씩 4개를 구해서 hashCode() 값을 구하고 있다.

fun main() {
    var personGeneral1 = PersonGeneral("devkuma", 21)
    var personGeneral2 = PersonGeneral("devkuma", 21)
    
    var personData1 = PersonData("devkuma", 21)
    var personData2 = PersonData("devkuma", 21)

    println(personGeneral1.hashCode())
    println(personGeneral2.hashCode())

    println(personData1.hashCode())
    println(personData2.hashCode())
}

Output:

1418481495
303563356
1111582818
1111582818
  • personGeneral1.hashCode(), personGeneral2.hashCode()의 반환 값이 다르게 반환 되었다.
  • personData1.hashCode(), personData2.hashCode()의 반환 값이 동일하게 반환 되었다.

equals()

equals()를 먼저 살펴보기 전에 kotlin 비교 연산자에 대해서 알아보겠다. Java와 Kotlin은 equals은 값과 메모리상 비교의 차이가 있다.

체크 대상 Java Kotlin
값이 동일한지 체크 .equals() == OR .equals()
메모리상 동일한 객체인지 체크 == ===

아래 예제에서는 data class에 동일한 값을 넣은 두 클래스를 비교 체크하고 있다.

fun main() {
    var personData1 = PersonData("devkuma", 21)
    var personData2 = PersonData("devkuma", 21)
    
    println(personData1 == personData2)
    println(personData1 === personData2)
}

Output:

true
false
  • ==을 사용하였을 때는 값이 동일한지 체크하고 있기에 true가 반환되었다.
  • ===을 사용해서는 메모리상으로 동일한 객체인지 체크하고 있기에 false가 반환되었다.

copy()

copy() 함수는 생성자에 정의된 프로퍼티 한해서 값을 변경하여 복사할 수 있다.

아예 예제에서는 데이터 클래스를 먼저 1개를 만들고, 두개에 클래스에 copy() 함수를 이용해서 프로퍼티 값을 복사하고 있다.

fun main() {
    val personData1 = PersonData("devkuma", 21)

    val personData2 = personData1.copy()
    val personData3 = personData1.copy(name = "kimkc")

    println(personData1)
    println(personData2)
    println(personData3)
}

Output:

PersonData(name=devkuma, age=21)
PersonData(name=devkuma, age=21)
PersonData(name=kimkc, age=21)
  • 첫번째 객체에 copy() 함수로 프로퍼티의 값을 복사하였다.
  • 두번째 객체에서는 copy(name = "kimkc") 함수에 name 값만 변경해서 프로퍼티의 값을 복사하였다.

데이터 분해 및 대입(Destructuring Declarations)

보통 객체에서 변수 값을 가져오려면 아래와 같이 할 것이다.

fun main() {
    val personData = PersonData("devkuma", 21)

    val name = personData.name
    val age = personData.age

    println("$name, $age years of age")
}

Output:

devkuma, 21 years of age

Kotlin에서는 데이터 분해 및 대입(Destructuring Declarations)을 지원하기에 아래와 같이 짧게 작성이 가능하다.

fun main() {
    val personData1 = PersonData("devkuma", 21)

    val (name, age) = personData1

    println("$name, $age years of age")
}

Output:

devkuma, 21 years of age
  • val (name, age) = personData1에 코드처럼 데이터 클래스의 값이 각각의 변수에 대입된다.

참조