Data Class

TRASALBY·2024년 3월 19일
0

학습내용 옮기기

목록 보기
2/8

Data Class

데이터를 다루는데 최적화된 형태로 코틀린에서 제공하는 클래스형태이다.

데이터 클래스는 아래의 요건을 충족하여야 한다.

  • 기본 생성자는 1개 이상의 매개변수를 가져야 한다.
  • 모든 기본 생성자 매개변수는 val 또는 var로 선언해야 한다.
  • abstract, open, sealed, inner 문법과 같이 사용할 수 없다.

상속이 불가능

위의 요건에 따라 데이터 클래스는 상속을 받을 수 없는데 그 이유는 다음과 같다.

  • 만약 Data Class A가 존재하고 이를 상속받는 Data Class B가 있다고 가정하자.
  • 두 Data Class는 각각의 함수들을 자동으로 생성하려 할 것이다.
  • 이때 B 클래스에서는 상속받은 부모클래스에서 이미 정의된 equals를 비롯한 함수들을 재정의 하려 할 것인데 이때 충돌이 발생하는 것이다.

만약 상속이 꼭 필요하다면 추상 클래스와 인터페이스등을 활용하여 Data Class가 각각의 함수를 구현할 수 있도록 하여 구현할 수 있다.

abstract class Base(open val data1:String)

data classA(override val data1:String):Base(data1)

data classB(override val data1:String, val data2:String):Base(data1)

제공하는 함수

equals(), hashCode(), toString(), copy(), componentN() 5가지의 유용한 함수를 내부에서 자동적으로 생성해 준다.

Data Class에서는 코딩하는 과정에서 캡슐화를 위해 필수적 이지만 직접 생성하기에는 번거로운 과정들을 내부에서 함수로 처리하여 직접 구현하지 않고 바로 사용할 수 있다.

equals()

참조 동일성이 아닌 객체의 동등성을 검사

  • 코틀린의 구조적 동등 연산자인 “==”을 사용해 호출할 수 있다.
  • a.equals(b) 는 a==b와 같은 동작을 수행한다.
  • 참조 동일성을 비교하기 위해서는 “===”을 사용할 수 있다.
  • 주 생성자가 아닌 프로퍼티의 값은 다르더라도 생성자의 값만 비교하여 같은지 확인한다.
fun main() {
    val user1 = User("이호성")
    val user2 = User("이호성")

    println("user1 : $user1")
    println("user2 : $user2")
    println("user1과 user2는 같다? ${user1 == user2}")
    user2.age+=1
    println("user1 : $user1")
    println("user2 : $user2")
    println("user1과 user2는 같다? ${user1 == user2}")
}

data class User(var name: String) {
    var age = 26

    override fun toString(): String {
        return "${this.name} ${this.age}"
    }
}

Untitled

필요하다면 equals와 hashCode를 재정의 하여 모든 프로퍼티를 비교할 수 있도록 해주어야 한다.

override fun equals(other: Any?): Boolean {
        if (other == null || other !is User) return false
        return this.name == other.name && this.age == other.age
    }

    override fun hashCode(): Int {
        return Objects.hash(name, age)
    }

hashCode()

hashCode란 객체를 구별하는 정수값(레퍼런스)을 말한다.

toString()

별도의 String변환 과정 없이 바로 문자열의 형태로 출력할 수 있다.

  • 기본적으로 주 생성자의 프로퍼티만 변환 된다.

copy()

객체의 복사본을 만들어 반환한다.

  • 리턴되는 객체는 얕은 복사로 진행된다.
  • 인자로 생성자에 정의된 프로퍼티를 넘길 수 이다.
  • 이 경우 해당 프로퍼티의 값만 변경되고 나머지 값은 동일하게 생성된다.

얕은 복사

Data Class의 copy는 얕은 복사 이기에 몇가지 문제가 발생할 수 있다.

fun main() {
    val user1 = User("이호성", 25, mutableListOf("이터널리턴", "오버워치", "DJMAX"))
    val user2 = user1.copy()
    
    user2.age = 26
    user2.game.add("마블스냅")

    println("user1 : $user1")
    println("user2 : $user2")
}

data class User(val name: String, var age: Int, val game: MutableList<String>)

Untitled

user2는 user1을 copy하여 생성하였고 user2의 age값과 game 값을 변경하였다.

하지만 출력된 결과를 보면 age값은 문제없이 변경되었지만 game의 경우 user1의 값까지 함께 바뀐 것을 확인할 수 있었다.

이를 통해 기본형 타입의 변수들은 깊은 복사를 통해 이루어지지만 그 외의 변수들은 얕은 복사로 이루어 지는 것을 알 수 있다.

copy를 재정의 하여 사용하는 것으로 깊은복사처럼 사용할 수 있다.

data class User(val name: String, var age: Int, val game: MutableList<String>) {
    fun copy() = User(name, age, game.toMutableList())
}

componentN()

구조분해를 통해 변수에 값을 대입할 수 있다.

val user1 = User("이호성", 25,mutableListOf("이터널리턴", "오버워치", "DJMAX"))
val name = user1.name
val age = user1.age
val game = user1.game

일반적으로 클래스 내의 변수를 다른 변수에 대입하기 위해서는 위와 같은 방식을 사용할 수 있다.

하지만 Data Class의 경우 구조분해를 지원하기 때문에 간단하게 표현할 수 있다.

val (name, age, game) = user1

괄호안에 선언된 변수들은 이름에 상관없이 생성자의 프로퍼티들이 순서대로 대입된다.

때문에 순서에 유의하며 사용해야 한다.

0개의 댓글

관련 채용 정보