6월 20일 - Kotlin2

Yullgiii·2024년 6월 20일
0
post-thumbnail

생성자

코틀린에서 생성자는 자바와 조금 다르다. 기본 생성자를 대체할 수 있는 init 블록을 제공하며, 생성자에 인자가 필요한 경우 인자처럼 받을 수 있다. 이를 주 생성자라 부른다.

기본 생성자와 init 블록

init 블록은 기본 생성자에서 수행할 작업을 정의할 수 있다. 예를 들면, 초기화 작업을 수행한다.

class Test {
    init {
        // 기본 생성자에서 수행할 작업
        // 예를 들면, 초기화
    }
}

class Test(a: Int) {
    init {
        println(a)
    }
}

생성자의 인자를 통한 프로퍼티 할당

생성자의 인자를 통해 클래스 내부의 프로퍼티에 값을 할당할 수 있다. 이는 프로퍼티 선언을 대신하며, 값 할당 또한 생성자 호출과 동시에 수행된다.

class Test(val a: Int, val b: Int) {
    // 생략..
}

추가 생성자

주 생성자 외에 다른 형태의 생성자가 필요한 경우 constructor 키워드를 사용해 선언할 수 있다.

class Test(val a: Int, val b: Int) {

    // a 값만 인자로 받는 추가 생성자.
    // 기본 생성자를 반드시 호출해야 한다.
    constructor(a: Int) : this(a, 0)

    // 두 인자의 값을 모두 0으로 지정하는 생성자.
    constructor() : this(0, 0)
}

추가 생성자는 인자와 프로퍼티를 함께 선언할 수 없다. 따라서 프로퍼티 선언이 필요한 경우 주 생성자에서 이를 처리해야 한다.

접근 제한자와 생성자

생성자 앞에 접근 제한자를 붙여 가시성을 변경할 수 있다.


class Test private constructor(val a: Int, val b: Char) {

    private constructor(a: Int): this(a, 0)

    constructor(): this(0, 0)
}

함수

메소드를 함수로 표현하며, 반환 값이 없을 경우 Unit을 사용한다. 이는 생략 가능하다.

상속 및 인터페이스

클래스의 상속과 인터페이스의 구현은 콜론(:)을 사용한다. 상속받는 경우 반드시 부모 클래스의 생성자를 호출해야 하며, 부모 클래스의 생성자는 super 키워드를 사용해 호출한다.

open class View

class MyView : View {
    constructor(context: Context) : super(context) {
        // 초기화
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        // 초기화
    }

    // 생성자가 여럿일 경우, this 키워드를 사용해 자기 자신의 생성자를 호출할 수 있다.
    constructor(context: Context) : this(context, null) {
        // 초기화
    }
}

오버라이드는 어노테이션 대신 override 키워드를 사용한다.

open 키워드

open 키워드를 사용해 클래스 혹은 함수의 상속 여부를 결정한다.

open class Parent {
    open fun foo() {
        println("Parent foo")
    }
}

class Child : Parent() {
    override fun foo() {
        println("Child foo")
    }
}

this 키워드

this 키워드는 클래스 자신을 지칭할 때 사용한다. 클래스 내에서 다른 클래스나 인터페이스의 객체를 동적으로 생성하여 사용하는 경우, 키워드를 사용하는 위치에 따라 this가 의미하는 클래스가 달라질 수 있다.

동반 객체(companion object)

코틀린은 클래스 내에 정적 필드나 정적 함수를 가질 수 없지만, 동반 객체를 사용하면 클래스 내 모든 멤버에서 접근할 수 있으며, 인스턴스 생성 없이 호출할 수 있는 함수를 작성할 수 있다.

class MyClass {
    companion object {
        fun create(): MyClass = MyClass()
    }
}

val instance = MyClass.create()

싱글톤

단 하나의 인스턴스만 생성되도록 제약을 두는 디자인 패턴으로, 코틀린에서는 object 키워드를 사용해 간편하게 선언할 수 있다.

object Singleton {
    val a = "a"

    fun aa() {
        println(a)
    }
}

val value = Singleton.a
Singleton.aa()

is 연산자

자료형을 확인하기 위해 사용한다. 특정 타입이 아닌 경우를 확인하기 위해서는 !is를 사용한다.

fun test(obj: Any) {
    if (obj is Int) {
        println("Int 입니다.")
    } else if (obj is Float) {
        println("Float 입니다.")
    }
}

as 연산자

특정 변수를 원하는 자료형으로 변환하는데 사용한다.

fun processNumber(number: Number) {
    val value: Int = number as Int
}

범위

특정 범위를 순회하거나 해당 범위 내에 특정 항목이 포함되어 있는지 확인할 때 사용한다.

val range: IntRange = 0..10  // 0<=n<=10
val range2: IntRange = 0 until 10  // 0<=n<10
val value: Boolean = 5 in range  // true
val value2: Boolean = 5 !in range2  // false

for (i in 5 downTo 1) {
    print(i)  // 54321
}

for (i in 5 downTo 1 step 2) {
    print(i)  // 531
}

예외

값을 반환할 수 있으며, checked exception을 따로 검사하지 않는다. 즉, 대부분의 예외를 try-catch 문으로 감싸 처리해야 했던 자바와 달리 코틀린에서는 이를 선택적으로 사용할 수 있다.

널 안전성

코틀린에서는 컴파일 단계에서 널 포인터 예외가 발생할 문제를 해결하기 위해 모든 타입에 명시적으로 널 허용 여부를 함께 표기하도록 한다.

널 허용 여부 표기

명시적으로 타입 뒤에 ?를 붙여 널 값을 가질 수 있도록 한다.

val a: String? = null
val b: String = "b"

// 아래 두 경우 컴파일 에러 발생
val name: String
val address: String = null

엘비스 연산자

널 값을 허용하지 않는 값 혹은 변수에 널 값을 반환할 수 있는 함수의 결과를 대입해야 하는 경우에 사용할 수 있다.

val value = foo ?: 0  // foo가 null일 때는 0을 반환

안전한 호출 연산자

널 값 확인을 위해 if문 사용을 하던 자바와 다르게 간편하게 처리 가능하다.

val foo = bar?.baz  // bar가 null이 아닐 경우에만 baz를 대입
foo?.bar()  // foo가 null이 아닐 경우에만 bar() 함수 호출

as? 연산자

자바에서 지원되지 않는 자료형으로 변환을 시도할 가능성이 있는 부분을 try-catch 블록으로 감싸서 처리한다. 코틀린에서는 as? 연산자를 사용해 간편하게 처리한다.

val foo: String = "foo"
val bar: Int? = foo as? Int  // 자료형 변환에 실패하므로 bar로 null 값이 할당된다.
val bar: Int? = foo as? Int ?: 0  // 변환 실패 시 기본값을 0으로 설정

널 값이 아님을 명시하기: 비 널 값 보증

널 값을 포함할 수 있는 타입을 널 값을 포함하지 않는 타입으로 변환하여 사용할 수 있다.

val foo: Foo? = ...
val nonNullFoo: Foo = foo!!  // foo는 널 값을 포함하지 않음을 보증

foo!!.bar()  // foo가 널 값이 아님을 보증하면서 bar() 함수 호출

lateinit 키워드

초기화 없이 변수(var)만 선언할 수 있다. 사용 전에 반드시 초기화를 해야 한다. 초기화를 하지 않은 채로 사용하려고 하면 NPE 예외가 발생하기 때문에 초기화 작업은 필수적이다.

코드 복사
class Test {
    lateinit var api: API

    fun process() {
        if (::api.isInitialized) {
            // 작업 수행. 초기화 됨.
        } else {
            // 작업 수행. 초기화 안됨.
        }
    }
}

So...

코틀린은 자바보다 간결하고 효율적인 문법을 제공하여 개발자가 더 쉽게 코드를 작성할 수 있도록 돕는다. 생성자, 널 안전성, 범위 연산자 등은 코틀린

profile
개발이란 무엇인가..를 공부하는 거북이의 성장일기 🐢

0개의 댓글