코틀린 언어 정리 2-6

data class

일반 클래스에서 기능을 제약하거나 자동으로 처리해 주는 부분을 추가하여, 데이터를 저장하거나 활용하는데 초점을 맞춘 클래스입니다.


제약 및 요구사항

  • 주생성자를 반드시 선언해야 합니다.

  • 주생성자의 매개변수는 1개 이상 이어야 합니다.

  • 주생성자의 모든 매개변수는 var 또는 val로 선언해야 합니다. 즉 매개변수와 프로퍼티를 동시에 선언해야 합니다.

  • 데이터 클래스는 abstract, open, sealed, inner 등으로 선언할 수 없습니다.

  • 컴파일러 자동 생성 함수가 있습니다.

    • 컴파일러는 주생성자에 선언된 프로퍼티에 대해 다음의 함수들을 자동 생성합니다.

    • equals() / hashCode()

      • 일반 클래스의 equals() 는 객체가 같은지 비교합니다.

      • 데이터 클래스의 equals()는 객체의 타입과 프로퍼티의 값이 같은지 비교합니다.

    • toString()

      • 클래스 이름과 프로퍼티 값을 문자열로 출력합니다.

    • componentN()

      • 데이터 클래스의 프로퍼티를 선언된 순서대로 가져올 때 사용합니다. ex. obj.component1(), obj.component2(), ...

    • copy()

      • 객체의 데이터를 복사하는 함수입니다. 주생성자와 매개변수가 동일합니다.

    • 주생성자의 매개변수와 동시에 선언한 프로퍼티만 컴파일러 자동 생성 구현에 적용됩니다. 즉 데이터 클래스 몸체에 선언한 프로퍼티는 이 함수들의 구현에 적용되지 않습니다.


  • 컴파일러 동작( 멤버 상속 관련 )

    • data class에 equals(), hashCode(), toString()을 구현 했거나 상위 클래스에 final로 구현된 것이 있다면 자동으로 생성하지 않고 기존의 것을 사용합니다.

    • 상위 클래스에 이미 open된 componentN()이 있고 하위 클래스( data class )와 호환되는 선언( 매개변수, 리턴 타입 )이어서 override 가능한 경우 자동으로 override 합니다. override가 불가능한 경우 에러가 발생합니다.

    • 이미 copy() 가 있는 클래스는 data class의 상위 클래스가 될 수 없습니다.( 코틀린 1.3 부터 금지 )


  • copy(), componentN() 을 직접 구현할 수 없습니다.



편의기능

부분 복사

copy 함수는 인자 없이 사용될 경우 주생성자에 선언된 프로퍼티 전체를 그대로 복사하여 객체를 생성하지만 아래와 같이 이름있는 인수를 이용하여 일부 프로퍼티의 값을 변경하면서 copy 함수를 실행할 수 있습니다.


예제

data class DataA ( var name: String, var age: Int, var company: String ) {}


fun test () {

   var obj: DataA = DataA("John", 25, "A Company")

   var obj1 = obj.copy(name="Jane")

}


구조 분해( Destructuring Declaration )

데이터 클래스의 프로퍼티를 각각 명시하지 않고 변수로 바로 꺼내는 기능입니다. ( 객체를 변수로 분해하는 기능 ) 코딩 양을 상당히 줄여줍니다.

내부적으로 componentN 함수가 이용됩니다.


예제

data class DataA ( var name: String, var age: Int, var company: String ) {}


fun test () {

   var obj: DataA = DataA("John", 25, "A Company")

   var obj1 = obj.copy(name="Jane")


   var (name, age, company) = obj1

   println("$name, $age, $company")


   println(name == obj1.component1())

   println(age == obj1.component2())

   println(company == obj1.component3())

}



표준 라이브러리

표준 라이브러리에서도 Pair, Triple과 같은 data class를 지원합니다.


예제

data class DataTest(val name: String, var age: Int, var company: String) {

   var propInBody: String = "propInBody in data class"


   init {

       propInBody = "propInBody in data class"

   }


   fun funTest() {

       println("DataTest::funTest")

   }

}


//fun main(args: Array<String>) {

fun test () {

   var obj = DataTest("Ree", 30, "unknown")

   println("$obj, ${obj.propInBody}")

   println("${obj.component1()}, ${obj.component2()}, ${obj.component3()}")

   obj.funTest()

   obj.propInBody = "propInBody modified" // 주생성자의 매개변수에 선언된 프로퍼티가 아닌 경우 copy함수에 적용되지 않습니다.

   var obj1 = obj.copy()

   println("${obj.component1()}, ${obj.component2()}, ${obj.component3()}")

   println("$obj1, ${obj1.propInBody}") // obj의 propInBody 를 수정하였으나 copy 함수 실행 시 적용되지 않았다.

   println("obj == obj1: ${obj == obj1}") // 주생성자의 매개변수에 선언된 프로퍼티가 아닌 경우 equals()함수에 적용되지 않습니다.

   var (name, age, company) = obj1 // 구조 분해 선언 지원

   println("$name: $age   $company")


   // 표준라이브러리의 Pair와 Tripple

   var pairObj: Pair<String, Int> = Pair(obj1.component1(), obj1.component2())

   println("${pairObj.first}, ${pairObj.second}")

   println("${pairObj.component1()}, ${pairObj.component2()}") // Pair 도 데이터 클래스이므로 componentN() 을 지원한다.

   var tripleObj: Triple<String, Int, String> = Triple(obj1.component1(), obj1.component2(), obj1.component3())

   println("${tripleObj.first}, ${tripleObj.second}, ${tripleObj.third}")

   println("${tripleObj.component1()}, ${tripleObj.component2()}, ${tripleObj.component3()}") // Triple 도 데이터 클래스이므로 componentN() 을 지원한다.

}


'코틀린( Kotlin )' 카테고리의 다른 글

코틀린 2-8 sealed class  (0) 2020.04.06
코틀린 2-7 enum class  (0) 2020.04.06
코틀린 2-5 interface  (0) 2020.04.05
코틀린 2-4 class - 생성자 호출 순서, Any  (0) 2020.04.05
코틀린 2-3 class - 상속  (0) 2020.04.04

+ Recent posts