이 포스팅은 고돈호 님의 이것이 안드로이드다 with 코틀린(한빛미디어)을 기반으로 작성되었습니다.

1.1 클래스

객체지향어언어와 마찬가지로 코틀린 역시 클래스를 지원한다. 클래스의 기본 구조는 다음과 같다.

class 클래스이름 {
    var 변수명
    fun 함수명(매개변수이름: 매개변수 타입): 반환형 {
    }
}

1.2 클래스의 작성

클래스를 사용하기 위해서 생성자가 필요한데 이 생성자는 프라이머리 생성자와 세컨더리 생성자로 나뉜다. 

 

프라이머리 생성자

프라이머리 생성자는 constructor 키워드를 사용하여 정의하고 조건에 따라 생략을 할 수 있다. 사용방법은 다음과 같다.

class Phone constructor(model: String) {

}

constructor 키워드를 생략할 수 있으며 init 블록에 생성자를 통해 파라미터를 넘길 수 있다. 다만 init가 필요 없다면 파라미터 앞에 val을 넣어 클래스 내부의 전체에서 해당 파라미터를 사용할 수 있다. 다음과 같다.

class Phone(val model: String) {
    fun printModel() {
       print("이름은 ${model} 입니다.")
       }
 }

 

세컨더리 생성자

세컨더리 생성자는 프라이머리 생성자와 다르게 constructor을 클래스 내부로 넣는 것이다. 예시는 다음과 같다.

class Phone {
    constructor (model: String) {
        Log.d("Class", "생성자로 부터 받은 model의 이름은 ${model} 입니다.")
        }
}

세컨더리 생성자는 메소드 오버로딩을 적용하여 여러 개를 중복할 수 있다. 다음과 같다.

class Phone {
    constructor (model: String) {
        Log.d("Class", "생성자로 부터 받은 model의 이름은 ${model} 입니다.")
        }
    constructor (model: Int) {
        Log.d("Class", "생성자로 부터 받은 model의 번호는 $[model} 입니다.")
        }
    constructor (model: String, model2: Int) {
        Log.d("Class", "생성자로 부터 받은 model의 이름은 ${model} 이고 번호는 ${model2} 입니다.")
        }
}

 

Default 생성자

생성자가 없는 경우 Default 생성자가 되며 파라미터가 없는 프라이머리 생성자와 동일하다.


1.3 클래스의 사용

클래스의 사용은 생성자를 호출하며 사용한다. 파라미터 없이 괄호를 붙이면 생성자가 호출되며 init 블록 안의 코드가 실행된다. 세컨더리 생성자는 init 블록이 먼저 실행되며 constructor 블록 안의 코드가 실행이 된다. 다음과 같이 클래스를 호출한 후 생성된 인스턴스를 변수에 담을 수 있다.

var variable = Class()

예시를 통해 사용법을 보면 다음과 같다. (.) dot 연산자를 통해 클래스 내부의 멤버 함수, 멤버 변수에 접근할 수 있다.

class Phone {
    var modelName: String = "Galaxy"
    fun printName() {
        Log.d("Class", "Phone의 이름은 ${modelName} 입니다."_
        }
 }
 
 var phone = Phone()
 phone.modelName = "iphone"
 phone.printName()

1.4 Object

자바의 static과 비슷하게 object를 아용하면 생성자로 인스턴스화 하지 않고 사용할 수 있다. 즉 클래스명에 dot 연산자를 이용하여 멤버 변수 및 멤버 함수에 접근이 가능한 것이다. 예시는 다음과 같다.

Object Phone {
    var modelName: String = "Galaxy"
    fun printName() {
        Log.d("Class", "Phone의 이름은 ${modelName} 입니다."_
        }
 }
 
Phone.modelName = "iphone"
Phone.printName()

단 Object는 한 앱 전체에 한개만 생성될 수 있다.


1.5 Companion Object

companion object를 사용하면 object와 마찬가지로 인스턴스의 생성 없이 사용할 수 있다.

여태까지 로그 출력을 위해 사용했던 Log.d 역시 Log 클래스 안에 object 코드 블록 안에 있기 때문에 바로 클래스명에 dot 연산자를 이용하여 사용할 수 있었다.


1.6 data 클래스

코틀린에서 간단한 값의 저장 용도로 data class를 사용할 수 있다. data 클래스의 형식은 다음과 같다.

data class 클래스 이름(val 파라미터: 파라미터형, val 파라미터2: 파라미터형)

위에서 보이듯 클래스 이름앞에 data class를 붙여야 하고 생성자의 파라미터에 var, val을 사용할 수 있다. 예시는 다음과 같다.

// 정의
data class SimpleDClass(val name: String, val model: Int)
// 생성
var simpleData = SimpleDClass("iphone", 13)

data class에 toString()을 사용하면 클래스의 실제 값을 반환한다.


1.7 클래스의 상속 & 확장

다른 언어에서의 클래스와 동일하게 코틀린의 클래스 역시 상속과 확장을 사용할 수 있다. 상속은 다음과 같이 사용할 수 있다. 부모 클래스의 경우 open 키워드를 사용해야 한다.

open class Parent {

}
class Child: Parent() {

}

부모 클래스의 생성자에 파라미터가 있는 경우 다음과 같이 사용할 수 있다.

open class Parent(value: String) {

}
class Child(value: String): Parent(value) {

}

상속을 사용하면 자식 클래스에서 부모 클래스의 멤버 변수, 멤버 함수를 사용할 수 있다. 예시는 다음과 같다.

open class Phone {
    var model: String = "modelName"
    fun call() {
        Log.d("inheritance", "${model} 으로 전화합니다.")
        }
}

class SmartPhone: Phone() {
    fun smartCall() {
        model = "iphone"
        call()
    }
}

1.8 오버라이딩

오버로딩과 말은 비슷하지만 오버라이딩은 상속에서 메서드를 재정의 하는 것을 의미한다. 만약 위의 예시에서 open class에 있는 call()와 이름이 같게 SmartPhone 클래스에서도 smartCall()를 call()로 변경하면 이것이 바로 오버라이딩 이다. 오버라이드에는 메서드 오버라이드와 프로퍼티 오버라이드가 있으며 이는 각각 다음과 같다.

 

메소드 오버라이드

open class ParentClass {
    open fun opened() {
    }
    fun notOpened() {
    }
}

class ChildClass: ParentClass() {
    override fun opened() {
    }
    override fun notOpened() { // notOpened는 parentClass에서 open이 아니므로 override할 수 없음
    }
}

프로퍼티 오버라이드 

메서드와 마찬가지로 프로퍼티 역시 오버라이드가 가능하며 이 역시 open으로 되어있어야만 오버라이드가 가능하다.

open class ParentClass2 {
    open var opened: String = "I am"
}
class ChildClass2: ParentClass2() {
    override var opened: String = "You are"
}

1.9 익스텐션

코틀린은 미리 만들어져 있는 클래스에 메서드를 넣는 익스텐션이 가능하다. 이때 이 클래스는 자신이 만든 클래스보다는 다른 사람이 작성한 이미 컴파일되어 있는 클래스에 메서드를 추가하기 위한 용도로 사용하는 것이 좋다. 예시는 다음과 같다.

class ExistClass {

    fun A()

    fun B()

                                                                   }

가 있고 이 클래스에 C()를 추가하고 싶으면 ExistClass.c() { } 이렇게 작성한다.

익스텐션의 예시 코드는 다음과 같다.

package kr.co.ki.function

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        testStringExtension()
    }

    fun testStringExtension() {
        var original = "Hello"
        var added = "World!"

        // plus 메서드를 사용하여 문자열 더하기
        Log.d("Extension", "added를 통해 문자열을 더한 값은 ${original.plus(added)} 입니다.")
    }
}

fun String.plus(word: String): String {
    return this + word
}

전체 코드는 다음과 같다.

package kr.co.ki.function

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //  부모 클래스 직접 호출
        var parent = Phone()
        parent.call()

        // 자식 클래스 호출해서 사용하기
        var child = SmartPhone()
        child.smartCall()

        testStringExtension()
    }

    fun testStringExtension() {
        var original = "Hello"
        var added = " World!"

        // plus 메서드를 사용하여 문자열 더하기
        Log.d("Extension", "added를 통해 문자열을 더한 값은 ${original.plus(added)} 입니다.")
    }
}

// 상속 연습
open class Phone {
    var model: String = "modelName"
    fun call() {
        Log.d("Extension", "${model} 으로 전화합니다.")
    }
}

class SmartPhone: Phone() {
    fun smartCall() {
        model = "iphone"
        call()
    }
}

// 메소드 오버라이드 연습
open class ParentClass {
    open fun opened() {
    }
    fun notOpened() {
    }
}

class ChildClass: ParentClass() {
    override fun opened() {
    }
    //override fun notOpened() { // notOpened는 parentClass에서 open이 아니므로 override할 수 없음
    //}
}

// 프로퍼티 오버라이드 연습
open class ParentClass2 {
    open var opened: String = "I am"
}
class ChildClass2: ParentClass2() {
    override var opened: String = "You are"
}
fun String.plus(word: String): String {
    return this + word
}

'안드로이드 앱 개발' 카테고리의 다른 글

9. 지연 초기화  (0) 2021.12.23
8. 코틀린의 null  (0) 2021.12.23
6. 함수  (0) 2021.12.20
5. 반복문  (0) 2021.12.19
4. 배열과 컬렉션  (0) 2021.12.14

+ Recent posts