지난 포스팅에서는 Kotlin의 Class 의 생성자와 상속에 대해 살펴봤다면

이번 포스팅에서는 Class의 여러 쓰임에 대해 알아보고자 합니다.

 

Data Class

data를 저장하기 위해 Class를 사용할 때가 많은데요. Kotlin에서는 이런 Class를 Data Class라고 부릅니다.

data class Customer(val name: String, val phone: String, val age: Int = 0)

 

컴파일러는 data class 를 선언하면 자동으로 primary constructor에 멤버함수를 생성합니다.

equals() / hashCode() / toString() / conponentN() / copy()

 

위의 자동으로 생성된 멤버함수의 동작을 위해 아래의 조건을 만족해야만 합니다.

- primary constructor 는 반드시 하나 이상의 인자를 가져야 합니다.

- 모든 primary constructor 는 val 혹은 var 선언이 되어야 합니다.

- Data class는 abstract, open, seal, inner class 이면 안됩니다.

(abstract class는 java와 동일하며, open class는 상속가능한 class, seal class는 inner class는 말 그대로 다른 class 내부의 class입니다.)

- Kotlin 1.1 이전에는 interface 구현만 가능했으나 Kotlin 1.1 부터는 다른 class 를 상속받아 구현하는 것이 가능합니다.

 

개발을 하다보면 객체를 복사해서 사용하는 경우가 많은데요.

일부만 복사하고 일부는 변경해서 사용 할 수 있습니다.

 

fun copy(name:String = this.name, phone: String = this.phone, age: Int = this.age) = Customer(name, phone, age)

 

위와 같은 copy 함수가 자동으로 생성되면 아래와 같이 사용 가능합니다.

val newCustomer = User(name = "Gil-Dong", phone = "0101112222", age = 24)
val addCustomer = newCustomer.copy(phone = "0102223333")

또한 Data class 에서는 아래와 같이 사용하여 변수에 Data class의 값을 얻어올 수 있습니다.

val checkCustomer = User("Gil-Dong", "0101112222", 24)
val (name, phone, age) = checkCustomer
println("customer info : $name, $phone, $age")

 

Sealed Class

sealed class 는 JAVA 에서도 들어본적이 없어서 생소한 이름인데요.

제한된 형태의 클래스를 나타내기 위해 사용됩니다. enum 의 확장이라고 생각하시면 됩니다.

enum 타입과 Sealed class 모두 값이 제한되지만, enum 상수는 단일 인스턴스로만 존재하고 sealed class의 하위클래스는 state를 포함하는 여러 인스턴스를  가질 수 있습니다.

Sealed class의 하위클래스는 Sealed class와 같은 파일에 선언해야만 합니다.

 

아래 예제 코드는 Expr 이라는 sealed class 가 선언되고,

Expr 을 상속받는 Const 클래스와, Expr을 상속받으며 인자로 Expr 을 받는 Sum 이라는 클래스가 있습니다.

또한 Expr 타입의 object도 선언해서 사용할 수 있습니다.

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber: Expr()

sealed class는 abstract class 이며 직접 인스턴스화 할수 없습니다. abstract class처럼 abstract member 를 가질 수 있습니다.

sealed class 를 상속받는 Const, Sum 은 같은 파일에 있어야 하지만, 이들을 상속받는 다른 클래스들은 동일한 파일에 있을 필요는 없습니다.

sealed class를 사용할때 큰 이점은 when 문을 사용할 때인데요.

아래 예제 코드에서 eval 함수는 Expr을 인자로 받아 Double 형을 리턴하는 함수입니다.

when 문에서 인자로 받은 expr 이 어떤 형태인지 아래와 같이 확인이 가능합니다.

JAVA로 하면 인자로 받은 expr 이 어떤 객체인지 확인을 하고 구현을 해야하는데 아래와 같이 구현이 가능하니

코드량이 확실히 줄어드는 것을 바로 확인할 수 있습니다.

fun eval(expr: Expr) : Double = when(expr) {
    is Const-> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NAN
}

 

'Language > Kotlin' 카테고리의 다른 글

[Kotlin] Range 사용하기  (0) 2018.01.25
[Kotlin] if, when, for, while 제어문 사용하기  (0) 2018.01.04
[Kotlin] 함수 사용하기  (0) 2017.12.28
[Kotlin] Class 사용하기  (0) 2017.12.15
안드로이드 공식 개발언어 Kotlin  (0) 2017.12.01

Kotlin 에서의 Class 사용에 대해서 알아보도록 하겠습니다.

Java 와의 호환성이 Kotlin 의 큰 장점으로 부곽되는 만큼 Java 와 비교하게 되는 부분이 있습니다.

 

Kotlin 에서 Class는 Java와 같이 아래처럼 사용합니다.

class Person{ }

그러나 Java 와 다르게 Body 가 없이 아래와 같이 사용될 수도 있습니다.

class Person

 

Kotlin에서는 primary constructor 과 하나 이상의 secondary constructor 를 가질 수 있습니다.

primary constructor 는 class 선언시 함께 가능합니다.

constructor 키워드는 생략 가능합니다.

annotation 이나 접근자(private, pubilc 등) 와 함께 사용되는 경우 생략할 수 없습니다.

class Person constructor(firstName: String) {

}
class Person(firstName: String) {

}

primary constructor

primary constructor 는 어떤 코드도 포함하지 않으므로 initializer block 을 사용하여 초기화 코드를 구현하면 됩니다.

constructor 가 불리면 객체 생성이 되면서 initializer block 이 불립니다.

primary constructor 의 parameter 는 class 내 어디서든(init 블럭이나 속성값 초기화) 사용 가능합니다.

class Person(name: String) {
    val nameInfo = "Name : $name".also(::println)

    init {
        println("First initializer block that prints ${name}")
    }

    val secondProperty = "Second property: ${name.length}".also(::println)

    init {
        println("Second initializer block that prints ${name.length}")
    }
}

 

secondary constructor

constructor 키워드가 반드시 사용되어야 합니다.

class Person {
    constructor(parent: Person) {
        parent.children.add(this)
    }
}

primary constructor 가 있는 경우 모든 second constructor는 primary constructor 에게 위임해야 합니다. 동일 클래스 내에서 다른 생성자로의 위임은 this 키워드를 사용합니다.

class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

initializer block의 코드는 primary constructor 의 일부가 된다. primary constructor 로의 위임은 secondary constructor 코드 실행 전에 실행되므로 모든 initializer block 의 코드는 가장 먼저 실행됩니다.

class Constructors {
    init {
        println("Init block")    // 먼저 실행됨
    }

    constructor(i: Int) {
        println("Constructor")   // 나중에 실행됨
    }
}

 

class의 instance 생성하기

class의 instance 를 생성하는데 JAVA에서는 new 키워드를 사용했다면, Kotlin 에서는 constructor 호출만 하면 됩니다.

val invoice = Invoice()

val customer = Customer("Joe Smith")

 

class 상속받기

Kotlin 에서 class 를 상속받기 위해서는 아래와 같이 사용할 수 있습니다.

C++과 같이 : 기호를 사용하는데 super class의 클래스명에 괄호기호가 붙는 점이 다르네요

물론 함수 override 도 아래와 같이 할 수 있습니다.

open annotation은 class로부터의 상속이 가능하다는 의미입니다. Kotlin에서는 모든 class가 default로 final 로 선언됩니다

open annotation을 사용하는 경우에만 상속이 가능합니다.

method 의 경우에도 open annotation이 있는 method 만 override 가능합니다.

open class Base {
    open fun v() {}
    fun nv() {}
}
class Derived() : Base() {
    override fun v() {}
}

변수의 경우 val 변수(Read only) 를 var 변수로 재정의 할 수 있지만, 반대는 안됩니다.

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}

 

 

+ Recent posts