Android 앱/Kotlin Language

kotlin 코틀린 - class 클래스

arvigoes 2020. 3. 2. 22:41

클래스 기초

기본자료형 Char, Byte, Short, Int, Long 등도 코틀린 내부에서 제공하는 클래스

클래스는 고유의 값을 담는 변수인 속성 (attribute) 과 기능을 구현한 함수 (function) 으로 이루어져 있습니다.

클래스는 instance 를 만드는 틀입니다.

우리가 기본자료형 Int, Long 등을 사용할때 Int 를 직접 사용하지 않았습니다.

var number : Int = 0   이렇게 변수를 만들어 사용하였습니다.

이 변수가 클래스의 인스턴스라고 생각하시면 이해가 쉽습니다.

var number2 :Int = 1  추가로 변수를 선언한다면 number 와 number2 는 같은 클래스 이지만

다른 값을 가지는 instance 입니다.

 

이제 Kotlin 에서 클래스를 만들어 보도록 하겠습니다.

 

class 이름 (속성리스트) {

      함수...

}

가장 기본적인 형태입니다.

kotlin 에서는 클래스 생성하는 형태가 참 다양해서 처음 부터 일반화 시켜보려고 하니 어렵네요

 

클래스를 한번 만들어 보도록 하겠습니다.

class Dog(var name:String, var owner:String) {

    fun nameTag() {
        println("name:${name}, owner:${owner}")
    }
    
}

fun main() {
    var mung = Dog("mung", "soju")
    
    println("name:${mung.name}, owner:${mung.owner}")
    
    mung.nameTag()
}

Dog 라는 클래스를 만들었습니다.

Dog 클래스의 instance mung 을 만들었습니다


attribute 는 name , owner 가 있네요

attribute 에 접근하는 방법은 instence . 속성이름 으로 접근 하시면 됩니다.

여기에서는 mung.name , mung.owner 가 되겠네요

println 으로 출력해보았습니다.

Dog 가 한개의 instance 만 있다면 println 한개만 있으면 되겠지만,

mung 이외에 wal, a, b, c, 등 여러마리라면 매번 println 으로 출력 해 주기가 귀찮아 집니다.

이럴때 사용하는게 function 입니다.

 

nameTag function 으로 만들어 사용 하면 편하게 사용 할 수 있습니다.

호출하는 방법은 attribute 접근 방식과 비슷한데 함수 이므로 함수 호출 방식으로 호출 해 주시면됩니다.

mung.nameTag()   : 파라미터가 있다면 (param, param ) 이렇게 호출 하시면 됩니다.

 

생성자

객체 지향 프로그래밍에서 객체의 초기화를 담당하는 서브루틴을 말합니다.

생성자는 객체가 처음 생성될 때 호출되어 속성을 초기화하고, 필요에 따라 특정 구문을 수행하기도 합니다.

객체의 생성 시에 호출되기 때문에 생성자라는 이름이 붙었습니다.

 

우리는 클래스를 선언할때 attribute list 를 추가 했습니다.

이때 추가된 attribute list 는 클래스 주생성자(primary constructor) 가 자동으로 만들어집니다.

//---------------------------------------
// 주 생성자(primary constructor) 
//---------------------------------------
class Dog(var name:String, var owner:String) {
}
//---------------------------------------
// constructor 가 쓰여져야 하나 생략 가능 합니다.
//---------------------------------------
class Dog2 constructor(var name:String, var owner:String) {
}

//---------------------------------------
// attribute 와 생성자 분리
//---------------------------------------
class Dog3(_name:String, _owner:String) {
    var name:String = _name
    var owner:String = _owner
}

 

위 3가지 클래스 생성자는 모두 동일하게 주생성자를 만들어 줍니다. 

 나중에 public, protected, private 등의 접근 제한자를 사용하려면,

3번째 attribute 분리 방법이 제일 보기 편해 3번째 방법을 주로 사용 합니다.

attribute 를 분리 하지 않으면 private var name:String 이렇게 길어지거든요

 

이전에 만든 클래스의 생성 코드를 한번 확인 해 볼까요?

var mung = Dog("mung", "soju")

위 3가지 생성자 모두 이 방식으로 객체 생성이 가능 합니다.

 

이렇게 생성된 주 생성자는 attribute 초기화만 수행이 가능하고, 생성될때 수행될 구문은 수행 할 수 없습니다.

이 경우를 위해 kotlin 은 init 이라는 키워드를 재공 합니다.

class Dog(var name:String, var owner:String) {
    init {
        println("call init")
    }
}

init 은 어떤 파라미터도 어떤 return 도 할 수 없는 함수로 생성시 자동으로 호출 됩니다.

 

 

주생성자가 있으면 보조생성자도 있겠죠?

이번에는 보조 생성자를 만들어 보도록 합시다.

보조 생성자는 왜 만들어야 할까요?

공원에서 개의 인스턴스를 생성 한다면 모든 개의 주인이 다르므로,

위 처럼 ("이름", "주인") 이렇게 생상하는게 편해 보입니다.

 

그러나 애견카페라면 어떨까요?

물론 주인이 대려오는 경우도 있지만 보통은 카페사장님의 개가 많을 것 같습니다.

class Dog(var name:String, var owner:String) {
    init {
        println("call init")
    }
    public constructor(name:String): this(name, "boss") {
        println("call sub constructor")
    }
}

instance 생성시 개의 이름만 입력 해 주면 자동으로 사장님 소유가 됩니다.

fun main() {
    var mung = Dog("mung", "soju")
    mung.nameTag()

    var baw = Dog("baw")
    baw.nameTag()
}

우선 결과 부터 보도록 할까요?

init 도 호출 되었고, sub 생성자 호출도 확인했습니다.

public constructor(name:String): this(name, "boss")

이제 이 구문을 좀 더 자세히 보도록 할까요?

보조 생성자는 자신의 수행영역 (중괄호 영역 {} ) 호출 이전에 주생성자를 무조건 호출 해야 합니다.

여기에서 this 는 instance 자체를 가르칩니다.

지금은 this 는 instance (예제에서는 baw ) 를 가르친다라고만 알고 넘어가도록 하겠습니다.

this(name, "boss") 가 this 의 주 생성자 (name:String, owner:String) 을 호출 하는 부분입니다.

보조생성자는 주생성자가 있다면 꼭 수행영역 전에 꼭 주생성자를 호출 해 주어야 한다!

잊지 마세요

 

보조생성자가 한개 밖에 없어 주생성자를 호출하는데 부담이 없지만 주 생성자를 만들지 않는다면

보조생성자를 만들어도 꼭 주생성자를 만들어 줄 필요가 없습니다.

이때 보조생성자는 보조 생성자라 하지않고 일반 생성자라 합니다.

class Dog{
    var name:String;
    var owner:String;

    init {
        println("call init")
    }
    public constructor(name:String, owner:String) {
        this.name = name
        this.owner = owner

    }

    public constructor(name:String) {
        this.name = name
        this.owner ="boss"
    }

    fun nameTag() {
        println("name:${name}, owner:${owner}")
    }
}

이 형태는 코틀린보다는 기존 언어 형태인데 여러 이점이 있을 수 있어 필요에 따라 선택 해서 사용 하시면됩니다.

제공되는 여러 기능을 상황에 맞게 잘 활용하는 것이 가장 중요하다고 생각합니다.