[Kotlin] data class와 주의사항


데이타 클래스(data class)란

  • Kotlin에서 데이터를 저장하는 목적으로 사용되는 특별한 종류의 클래스. 데이터 클래스는 일반 클래스와 달리 몇가지 유용한 기능을 자동으로 제공함.

데이타 클래스의 특징

  1. 간단한 선언: data 키워드를 사용하여 쉽게 선언

    data class Person(val name: String, val age: Int) 
  2. 자동 생성 메소드: 컴파일러가 아래의 메소드를 자동으로 생성

    • toString()
    • equals()
    • hashcode()
    • componentN() 함수들
  3. 불변성: 주 생성자의 파라미터를 val로 선언하여 불변 객체를 만들 수 있음

    • var로 선언하는 경우 해시 기반 컬랙션에서 예상치 못한 동작이 발생할 수 있다.
  4. Destructuring (구조분해): 데이터 클래스의 속성을 쉽게 분해할 수 있다.

    val persion = Person("Alice", 30)
    val (name, age) = person 
    

data class 사용 예시

data class User(val name: String, val id: Int) 

fun main(){ 
  val user1 = User("John", 1) 
  val user2 = User("John", 1) 

  println(user1) // User(name=John, id=1)
  println(user1 == user2) //true

  val user3 = user1.copy(name = "Jane")
  println(user3) // User(name=Jane, id=1) 

user1 == user2 에서 자동 생성된 equals method 가 사용 되는데, 이때 객체 비교를 메모리 주소로 하는것이 아니라 을 기준으로한다.


data class의 제한 사항

  • Primary Constructor(주 새성자)는 최소 하나의 파라미터를 가져야한다.
  • 모든 Primary Constructor는 val 또는 var로 표시되어야한다.
  • data class는 abstract, sealed, inner class가 될 수 없다.

data class가 자동 생성하는 메소드

toString()

  • data class는 모든 프로퍼티를 포함하는 가독성 좋은 문자열 표현을 제공한다.
  • Primary Constructor에 정의된 프로퍼티를 표시해준다.
  • 필요하다면 override해서 사용할 수 있다.
data class User(val name:String, val age: 25) 

val user1 = User("Alice", 25)
println(user1.toString()) 
// output: User(name=Alice, age=25) 

hashCode()

  • Primary Constructor에 정의된 모든 프로퍼티를 사용하여 해시코드를 계산한다.
  • 필요한 경우 override해서 커스터 마이징 할 수 있다. 하지만 이 경우 equals() 메소드와의 일관성 유지가 필요하다.

  val user1 = User("John", 1) 
  val user2 = User("John", 1)
  val user3 = User("Alice", 2) 

  println(user1.hashCode()) // ex: 421124123
  println(user2.hashCode()) // ex: 421124123 user1과 같은 값 
  println(user3.hashCode()) // ex: -127486178 user1과 다른  값 

  val userSet = hashSetOf(user1, user2, user3)
  println(userSet.size) // 2 user1과 user2는 동일한 것으로 간주됨

equals()

  • 구조적 동등성을 판단한다 : 객체의 내용을 비교하여 동등성을 판단한다. 모든 프로퍼티의 값이 같으면 동등하다고 간주한다.
  • Primary Constructor에 정의된 모든 프로퍼티를 비교에 사용한다.
  • type safe : 비교하는 객체의 타입을 먼저 확인한다.
  • null safe : null에 대한 안전한 비교를 수행한다.
  • hashCode()와 일관성: equals()가 true르 반환하는 두 객체는 반드시 같은 hashCode()를 가져야한다.
  val person1 = Person("Alice", 30)
  val person2 = Person("Alice", 30)
  val person3 = Person("Bob", 25)

  println(person1 == person2) // true
  println(person1 == person3) // false
  println(person1.equals(person2)) // true
  println(person1.equals(person3)) // false

copy()

  • 불변성 유지: 원본 객체를 변경하지 않고 새로운 객체를 생성.
  • 선택적 파라미터: 변경하고자 하는 속성만 지정할 수 있음
  • type safe: 컴파일시 타입체크가 이루어짐
  • 모든 프로퍼티 복사 : 명시적으로 변경하지 않은 프로퍼티는 원본 객체의 값을 그대로 유지
  data class Person(val name: String, val age: Int, val city: String)

  val alice = Person("Alice", 30, "New York")

  // 나이만 변경
  val olderAlice = alice.copy(age = 31)
  println(olderAlice) // Person(name=Alice, age=31, city=New York)

  // 도시만 변경
  val aliceInLondon = alice.copy(city = "London")
  println(aliceInLondon) // Person(name=Alice, age=30, city=London)

  // 여러 속성 변경
  val bobInParis = alice.copy(name = "Bob", age = 25, city = "Paris")
  println(bobInParis) // Person(name=Bob, age=25, city=Paris)

copy의 주의사항

  • copy():는 shallow copy를 수행한다. 중첩된 객체나 컬랙션은 참조만 복사된다.

  • 복사를 너무 많이하면 성능에 악영향이 있을 수 있다.

  • 변경되지 않은 값은 그대로 사용한다.

    • 파라미터로 전달된 값만을 변경하고, 변경되지 않은 필드는 원본 객체 값을 그대로 사용한다.
    • 이 방식으로 불필요한 객체 생성 작없을 회피한다.
      data class User(val name: String, val age: Int)
    
      val user1 = User("Alice", 25)
      val user2 = user1.copy(age = 30)
    
      println(user1.name === user2.name) // true, name 필드는 그대로 재사용
    
      data class LargeData(val id: Int, val name: String, val description: String)
    
      val large1 = LargeData(1, "Test", "This is a large data object.")
      val large2 = large1.copy(description = "Updated description.")
    
      println(large1.id === large2.id)        // true, id 필드는 그대로 재사용
      println(large1.name === large2.name)    // true, name 필드도 그대로 재사용
      println(large1.description === large2.description) // false, 변경된 description만 새로 생성

    `* == 값 동등성 비교 / === 참조 동등성 비교

반응형

'웹프로그래밍 > Kotlin' 카테고리의 다른 글

[KOTLIN] CLASS  (0) 2023.02.25
[코틀린 KOTLIN 정리]01.코틀린 시작하기  (0) 2021.06.02
[코틀린KOTLIN 정리]0. 들어가며  (0) 2021.06.02

Kotlin에서 Class는 객체지향 프로그래밍의 기본 요소입니다. Class는 데이터와 이를 다루는 함수들을 묶어서 캡슐화하고, 관련 있는 메서드와 속성을 함께 묶어서 구성합니다. 또한, Class를 통해 생성된 객체는 인스턴스라고 하며, 객체는 독립적인 메모리 공간을 가지고 있어서 서로 영향을 주지 않습니다.

Kotlin에서 Class를 선언할 때는 "class" 키워드를 사용합니다. 아래는 Kotlin에서 Class를 선언하는 예시입니다.

class Person {
    var name: String = ""
    var age: Int = 0

    fun sayHello() {
        println("Hello, my name is $name and I'm $age years old.")
    }
}

위 예시에서는 "Person"이라는 Class를 선언했으며, Class 내부에는 "name"과 "age"라는 변수와 "sayHello()"라는 함수가 포함되어 있습니다.

Class를 사용하면 코드의 재사용성이 높아지고, 유지보수가 용이해집니다. 또한, 객체지향 프로그래밍에서는 상속을 통해 기존 Class를 확장할 수 있으므로 코드의 재활용성이 더욱 높아집니다.

Kotlin에서는 Class를 선언할 때 추가적으로 상속을 지정할 수 있습니다. 상속을 위해서는 콜론 ":"을 사용하며, 상속할 부모 Class를 지정합니다. 예를 들어, 아래와 같이 Person Class를 상속받는 Student Class를 선언할 수 있습니다.

class Student : Person() {
    var grade: Int = 0
    var major: String = ""

    fun introduce() {
        println("I'm a student, my grade is $grade and my major is $major.")
    }
}

위 예시에서는 Person Class를 상속받는 Student Class를 선언했습니다. Student Class 내부에는 "grade"와 "major"라는 변수와 "introduce()"라는 함수가 추가되어 있습니다.

이처럼 Kotlin에서는 Class를 사용하여 객체지향 프로그래밍을 구현할 수 있습니다.

반응형

코틀린 시작하기

코틀린의 특징

  • Java와 형태는 다르나 의미가 유사한 문법을 가지고있기때문에 Java개발자라면 쉽게 학습이 가능하다.
  • 클래스 상속 없이 클래스에 도메인 특화 편의 메소드 추가가 가능하고, 오리지날 클래스의 메소드터럼 사용할 수 있다.
  • 델리게이션을 지원해서 상속보다 더 좋은 디자인이 가능하다. 델리게이션은 타입 안정적으로 사용할 수 있다.
  • if-else 문 대신 argument-matching문법을 사용할 수 있다.
  • 이미 존재하는 함수를 확장하는것이 쉽게 가능하다. 기본 파라미터 기능이 있다.
  • 명시적 인자 사용이 가능하다.
  • 연산자 오버로딩이 가능하다.
  • 우아하고, 표현력이 강하고, 간결하다.
  • C스타일의 프로시저, 스칼라 스타일의 스크립트, Java같은 객체지향형 코드, 스몰톡/얼랭과 같은 함수형 스타일 코드 모두 사용 가능하다.
  • 코루틴과 컨티뉴에이션으로 비동기 프로그래밍 영역에서 혁신을 이끌고 있다.

코틀린이 좋은 이유(와 나의 생각)

  • 다양한 프로그래밍 패러다임
    • 객체지향,함수형, 절차지향, 스크립트, 비동기 프로그래밍 등 다양한 프로그래밍 페러다임을 제공하기때문에 그중 상황에 맞는 방식을 사용하면된다.
    • 보일러 플레이트 코드가 없다.
    • 더 적은 코드로 동일한 일을 할 수 있다.
  • 타입 추론으로 사용하는 정적 타입
    • 강력한 타입 추론을 해주기때문에 시간낭비할 필요가 없다.
    • 타입 추론이 명확하지 않은 경우 개발자에게 타입 명시를 요청한다.
    • 널러블 / 널불가 타입이 구분되어있다.
  • 풀스택 개발을 위한 히나의 언어.
    • 한번의 코드 작성으로 백엔드, 모바일, 네이티브, 웹어셈블리 등의 코드로 컴파일(혹은 트랜스파일)이 가능하다.
    • ( 가능하긴하나 아직 적극적으로 사용하긴 조금 어려운 부분이 있지 않은가 하는 생각이 든다.)
  • 자연스럽고 우아함
    • 보일러플레이트 코드가 필요 없다.
    • 세미콜론이 옵셔널이다
    • 인픽스 어노테이션 사용이 가능하다.

코틀린 설치 및 사용

  • 인텔리J를 사용중이라면 함게 설치되어있다.
  • 별도로 설치를 원하면 https://kotlinlang.org 에서 다운로드 및 설치할 수 있다. 자세한 설치방법은 공식 홈페이지를 참고하도록하자.

설치 확인

cli에서 다음과 같이

kotlinc-jvm -version

본인의 경우는
info: kotlinc-jvm 1.4.31 (JRE 15.0.2+7)
이렇게 출력이 나왔다.

우리가 늘 하는 Hello World 만들기

적절한 폴더에 hello.kt라는 파일을 만들고 아래와 같이 코드를 넣어본다.

//hello.kt
fun main() = println("Hello World")

cli로 실행시키기

kotlinc-jvm hello.kt -d hello.jar

위 명령어를 실행시키면 hello.kt 코틀린 코틀린코드를 Java바이트 코드로 컴파일시키고 hello.jar를 만들어둔다.
jar를 java툴을 이용해서 실행시키면된다.

java -classpath hello.jar HelloKt

hello.kt는 main함수만 가지고있고, 클래스가 아니기때문에 코틀린 컴파일러가 자동으로 확장자를 제거한 파일 이름을 가지고 Kt라는 접미사를 추가한 클래스이름을 만든다.

실행결과는 당연히
Hello World가 나온다.

classpath cli옵션을 열거하지않고, jar옵션으로 실행 가능하다. main()함소를 찾을때 코틀린 컴파일러가 jar 파일에 Main-Class 매니패스트 어트리뷰트를 추가한다.

java -jar hello.jar

현재는 코틀린 스탠다드 라이브러리를 사용하지 않았기 때문에 실행이 잘 되지만 코틀린 스탠다드 라이브러리의 클래스와 함수들을 사용하는 경우 java툴로만 실행한다면 java.lang.NoClassDefFoundError예외가 발생하면서 실패한다. 이를 방지하기위해서는 kotlin-stdlib.jar파일을 클래스패스에 추가해줘야한다.

kotlinc-jvm hello.kt -d hello.jar
java -classpath hello.jar:$KOTLIN_PATH/lib/kotlin-stdlib.jar HelloKt
//위도우인경우 %KOTLIN_PATH% 를 사용, 콜론(:)이 아닌 세미콜론(;)으로 구문해야한다. 등록된 환경변수를 사용하면된다.

ide로 실행하기

코틀린 공식 홈페이지 및 각 ide의 홈페이지와 라이브러리를 참고하면 될거같다. 여기서는 굳이 언급하지 않도록하겠다.

REPL실험

cli에서 kotlinc-jvm 이라고 입력하면 REPL이 실행된다.
아래와같이 조금 사용해보자.

//kotlinc-jvm
Welcome to Kotlin version 1.4.31 (JRE 15.0.2+7)
Type :help for help, :quit for quit
>>> 7 + 5
res0: kotlin.Int = 12
>>> val list = listOf(1,2,3)
>>> list.map{ it * 2}
res2: kotlin.collections.List<kotlin.Int> = [2, 4, 6]
>>>

종료할땐 컨트롤D 를 사용하거나 :quit 라고 입력한다.

REPL에선 이미 존재하는 코드를 불러와서 실행시킬수도 있다.

kotlinc-jvm

Welcome to Kotlin version 1.4.31 (JRE 15.0.2+7)
Type :help for help, :quit for quit
>>> :load hello.kt
>>> main()
Hello World!
>>>

이렇게 REPL에선 존재하는 코드를 컴파일 없이 실행할 수 있다.

스크립트로 실행하기

코틀린은 스크립트로 사용가능하다. 여타 스크립트에 비해서 좋은점이라면 스크립트를 위해 따로 문법 공부를 할 필요가 없다는 점이 있을것이고, 코틀린 스크립트는 문법 오류가 있는 경우 스크립트 실행 전에 실패를하기때문에 컴파일 후 칠행하는것 만큼 안전하다.

연습을 위해서 디렉토리에서 .kts 확장자를 가진파일을 리스팅 하는 스크립트를 만들어보자.

//listktsfile.kts
java.io.File(".")
    .walk()
    .filter { file -> file.extension =="kts" }
    .forEach { println(it) }

지금까지 작성한 코틀린 파일과 별반 타이가 없다. 차이점이라면 확장자가 kts라는것 뿐이다.
이 코드는 JDK의 java.io 패키지의 File 클래스를 사용한다. 그리고 코틀린이 해당 클래스에 추가한 확장 함수를 사용한다.
현재 디렉토리에 있는 모든 파일중 파일명이 kts로 끝나는 파일만 걸러내서 잡고 해당 파일의 경로를 출력한다.

스크립트 실행을 위해선 kotlinc-jvm 커맨드를 사용한다. -script옵션을 통해서 컴파일 대신 스크립트로써 즉시 실행시킨다.

kotlinc-jvm -script listktsfiles.kts

Unix-Like 시스템을 사용한다면 kotlinc-jvm -script라는 접미어 대신 셔뱅(shebang)을 사용하면된다.

greeting.kts

#!/ust/bin/env kotlin-jvm -script
println("hello")

실행을위해 chmod +x greeting.kts 명령어로 파일에 실행권한을 주고 아래의 커맨드라인을 통해 스크립트를 바로 시킬 수있다.

./greeting.kts

시스템에 따라 /usr/bin/env 대신 kotlinc-jvm이 위치한 전체경로를 써줘야 하는 경우도 있다.

다른 타깃으로 컴파일하기

코틀린은 여러개의 타깃으로 컴피일이 가능한 언어이다.

  • 안드로이드
  • javascript로 트랜스파일
  • 네이티브 타깃(iOS, Linux, MacOS, Windows 등 네이티브 타겟)
  • WebAssembly

어떤 옵션을 선택해야할까?

코틀린은 실행시킬때 특정 옵션 설정을 강제하지 않기때문에 개발자의 요구사항과 선호도에 따라 실행옵션을 선택하면된다.
아래는 옵션 선택시 고려해야할 사항이다.

  • JVM에서 실행시키거나 Java또는 다른 언어와 함께사용하는경우 --> kotlinc-jvm을 이용한다.
  • 여러개의 코틀린 파일을 통합해 하나의 코틀린 프로그램으로 실행시켜야한다 -> kotlin툴을 이용한다.
  • 시스템레벨 / 백엔드 태스크 수형해야한다 -> 스크립트

정리

코틀린의 특징에 대해 알아보았고, 간단한 코드를 작성해보았다. 다음번엔 코틀린의 특징을 좀더 자세하게 알아보고 좀더 많은 코드를 작성해본다.

 

영진닷컴 - 다재다능 코틀린 프로그래밍 - 스프링 분철선택

COUPANG

www.coupang.com

쿠팡 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있습니다.

반응형

'웹프로그래밍 > Kotlin' 카테고리의 다른 글

[Kotlin] data class와 주의사항  (1) 2024.12.02
[KOTLIN] CLASS  (0) 2023.02.25
[코틀린KOTLIN 정리]0. 들어가며  (0) 2021.06.02

앞으로 코틀린에 대한 정리 글을 좀 올려보려합니다. 
정리는 영진닷컴에서 출판한 다재다능 코틀린 프로그래밍 서적을 기반으로 제가 이해한 내용을 정리합니다. 

 

 

 

 

영진닷컴 - 다재다능 코틀린 프로그래밍 - 스프링 분철선택

COUPANG

www.coupang.com

쿠팡 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있습니다.

반응형

'웹프로그래밍 > Kotlin' 카테고리의 다른 글

[Kotlin] data class와 주의사항  (1) 2024.12.02
[KOTLIN] CLASS  (0) 2023.02.25
[코틀린 KOTLIN 정리]01.코틀린 시작하기  (0) 2021.06.02

+ Recent posts