Kotlin

Kotlin - 데이터 클래스(Java의 POJO)와 기타클래스

J_Bin 2022. 6. 17. 18:00

# 데이터 전달을 위한 객체를 DTO(Data Transfer Object)라고 한다.

- 프로퍼티를 위한 게터/세터

- 프로퍼티를 문자열로 변환해 순서대로 보여주는 toString()

- 객체 복사를 위한 copy()

- 프로퍼티에 상응하는 componet1()...component2()...등

 

- 주 생성자는 최소한 하나의 매개변수를 가져야 한다.

- 주 생성자의 모든 매개변수는 val, var로 지정된 프로퍼티여야 한다.

- 데이터 클래스는 abstract, open, sealed, inner 클래스를 사용할 수 없다.

 

- 데이터 클래스가 자동 생성하는 메서드

1. eqauls() : 두 객체의 내용이 같은지 비교하는 연산자(고유 값(주소)은 다르지만 의미 값(value)이 같을 때)

2. hashCode() : 객체를 구별하기 위한 고유한 정숫값 생성, 데이터 세트나 해시 테이블을 사용하기 위한 하나의 생성된 인덱스

3. copy() : 빌더 없이 특정 프로퍼티만 변경해서 객체 복사하기

4. toString() : 데이터 객체를읽기 편한 문자열로 반환하기

5. componentN() : 객체의 선언부 구조를 분해하기 위해 프로퍼티에 상응하는 메서드

 

 

# 중첩 클래스 : 기본적으로 static(객체 생성 없이 접근 가능)

package chap02.section1

class Outer {
    val ov = 5

    class Nested {
        val nv = 10
        fun greeting() = "[Nested] Hello! $nv"              // 외부의 ov는 접근불가
    }

    fun outside() {
        val msg = Nested().greeting()                       // 객체 생성 없이 중첩 클래스의 메서드 접근
        println("[Outer] : $msg, ${Nested().nv}")           // 중첩 클래스의 프로퍼티 접근
    }
}



fun main() {

    // static처럼 객체 생성 없이 사용
    val output = Outer.Nested().greeting()
    println(output)

    val outer = Outer()
    outer.outside()




}

 

# 이너 클래스 : inner 키워드 사용, 바깥 클래스의 멤버들에 접근 가능, 심지어 private 멤버도 접근 가능

package chap02.section1

class Smartphone(val model : String) {
    private val cpu = "Exynos"

    inner class ExternalStorage(val size : Int) {
        fun getInfo() = "${model}: Installed on $cpu with ${size}Gb"        // 바깥 클래스의 프로퍼티 접근
    }
}



fun main() {

    val mySdcard = Smartphone("S7").ExternalStorage(32)
    println(mySdcard.getInfo())



}

 

# 지역 클래스 : 특정 메서드의 블록이나 init 블로고가 같이 블록 범위에서만 유효한 클래스이다.

블록 범위를 벗어나면 더 이상 사용되지 않는다.

 

package chap02.section1

class Smartphone(val model : String) {
    private val cpu = "Exynos"

    fun powerOn(): String {
        class Led(val color : String) {     // 지역 클래스 선언
            fun blink(): String = "Blinking $color on $model"       // 외부 프로퍼티 접근 가능
        }
        val powerStatus = Led("Red")        // 여기에서 지역 클래스가 사용됨
        return powerStatus.blink()
    }

    inner class ExternalStorage(val size : Int) {
        fun getInfo() = "${model}: Installed on $cpu with ${size}Gb"        // 바깥 클래스의 프로퍼티 접근
    }
}



fun main() {

    val mySdcard = Smartphone("S7").ExternalStorage(32)
    println(mySdcard.getInfo())

    val myphone = Smartphone("Note9")
    myphone.ExternalStorage(128)
    println(myphone.powerOn())

}

/*
    여기서 사용된 Led 클래스는 Smartphone 클래스의 메서드인 powerOn()에서만 유효한 클래스이다.
    단, Led 클래스에서 외부의 멤버인 프로퍼티에는 접근 가능하다.(Smartphone 클래스의 model : 외부 프로퍼티)
* */

 

# 익명 객체

package chap02.section1

class Smartphone(val model : String) {
    private val cpu = "Exynos"

    fun powerOn(): String {
        class Led(val color : String) {     
            fun blink(): String = "Blinking $color on $model"       
        }
        val powerStatus = Led("Red")        
        val powerSwitch = object : Switcher{        // (2) 익명 객체를 사용해 Switcher의 on()을 구현
            override fun on() : String {
                return powerStatus.blink()
            }
        }
        return powerSwitch.on()     // 익명 객체의 메서드 사용
    }

    inner class ExternalStorage(val size : Int) {
        fun getInfo() = "${model}: Installed on $cpu with ${size}Gb"        
    }
}

interface Switcher {        // (1) 인터페이스 선언
    fun on() : String
}



fun main() {

    val mySdcard = Smartphone("S7").ExternalStorage(32)
    println(mySdcard.getInfo())

    val myphone = Smartphone("Note9")
    myphone.ExternalStorage(128)
    println(myphone.powerOn())

}

/*
        (1)번에서 스위치를 위한 인터페이스 Switcher을 선언. 이후 Smartphone 클래스의 powerOn() 메서드를 수정
        (2)번에서 object를 사용해 Switcher 인터페이스의 on()메서드를 구현하고 있다.
        따라서 Switcher 인터페이스로부터 만들어진 객체는 이름이 없으며 powerSwitch 프로퍼티를 위해 일회성으로 사용된다.
        이 메서드가 호출될 때마다 일회성 객체의 인스턴스가 만들어진다.
        

* */

# 실드(Sealed) 클래스 : '봉인된'이라는 의미로 무언가 안전하게 보관하기 위해 묶어 두는 것을 말한다.

실드 클래스는 미리 만들어 놓은 자료형들을 묶어서 제공하기 때문에 어떤 의미에서는 열거형(Enum) 클래스의 확장으로도 볼 수 있다.

 

package chap02.section1

import chap02.section1.Result

/* 실드 클래스의 선언 */


/* 실드 클래스를 선언하는 첫 번째 방법 */
sealed class Result {
    open class Success (val message : String) : chap02.section1.Result()
    class Error (val code : Int, val message : String) : chap02.section1.Result()
}

class Status : chap02.section1.Result()
class Inside : chap02.section1.Result.Success("status")
/* 실드 클래스를 선언하는 첫 번째 방법 */



/* 실드 클래스를 선언하는 두 번째 방법 */
/*
sealed class Result

open class Success(val message : String) : chap02.section1.Result()
class Error (val code : Int, val message: String) : chap02.section1.Result()

class Status : chap02.section1.Result()
class Inside : Success("status")
*/
/* 실드 클래스를 선언하는 두 번째 방법 */



fun main() {

    val result = Result.Success("Good")
    val msg = eval(result)
    println(msg)

}

/*  실드 클래스는 특정 객체 자료형에 따라 when문과 is에 의해 선택적으로 실행할 수 있다.
    여기에서는 모든 경우가 열거되었으므로 else문이 필요 없다. 만일 이것을 이너 클래스나 중첩 클래스로 구현하려고 하면
    모든 경우의 수를 컴파일러가 판단할 수 없어 else문을 가져야한다. 하지만 실드 클래스를 사용하면 필요한 경우의 수를 직접 지정할 수 있다.
* */
fun eval(result : chap02.section1.Result) : String = when(result) {
    is Status -> "in Progress"
    is chap02.section1.Result.Success -> result.message
    is chap02.section1.Result.Error -> result.message



}

/*  실드 클래스를 선언하려면 sealed 키워드를 사용
    실드 클래스 그 자체는 추상 클래스와 같기 때문에 객체를 만들 수 없다.
    또한, 생성자도 기본적으로 private이며 private가 아닌 생성자는 허용하지 않는다.
    실드 클래스는 같은 파일 안에서는 상속이 가능하지만, 다른 파일에서는 상속이 불가능하게 제한된다.
    블록 안에 선언되는 클래스는 상속이 필요한 경우 open 키워드로 선언될 수 있다.
* */

# 열거형 클래스 : 여러 개의 상수를 선언하고 열거된 값을 조건에따라 선택할 수 있는 특수한 클래스.

열거형 클래스는 enum 키워드와 함께 선언할 수 있고 다음과 같이 자료형이 동일한 상수를 나열할 수 있다.

 

package chap02.section1

/* 인터페이스를 통한 열거형 클래스 구현하기 */

interface Score {
    fun getScore() : Int
}

enum class MemberType(var prio: String) : Score {
    NORMAL("Third"){
        override fun getScore(): Int = 100
    },
    SILVER("Second"){
        override fun getScore(): Int  = 500
    },
    GOLD("First") {
        override fun getScore() : Int = 1500
    }
}



fun main() {

    println(MemberType.NORMAL.getScore())
    println(MemberType.GOLD)
    println(MemberType.valueOf("SILVER"))
    println(MemberType.SILVER.prio)

    for (grade in MemberType.values()) {
        println("grade.name = ${grade.name}, prio = ${grade.prio}")
    }



}

 

'Kotlin' 카테고리의 다른 글

Kotlin - 제네릭  (0) 2022.06.20
Kotlin - 여러 연산자들의 표현  (0) 2022.06.20
Kotlin - 추상클래스와 인터페이스 ★  (0) 2022.06.15
Kotlin - 컴패니언 객체  (0) 2022.06.15
Kotlin - by(위임), 클래스의 위임 ★  (0) 2022.06.15