Kotlin

[Kotlin] 코틀린 문법 정리 - 02

728x90

 

 

1. 클래스를 상속하는 객체

 클래스 없이 object 표현식을 사용해 상속을 할 수 있다. 이때의 상속은 1회용이 된다.

open class Person(val name: String, val age: Int) {
    open fun print() {
        println("이름:$name, 나이:$age")
    }
}

fun main(args: Array<String>) {
    val custom: Person = object : Person("Alan", 23) {
        override fun print() {
            println("it's a object")
        }
    }
    custom.print()
}

 

 

2. Any 클래스

 모든 코틀린 클래스들은 Any 클래스를 상속한다.

open class Any {
    open operator fun equals(other: Any?): Boolean
    open fun hashCode(): Int
    open fun toString(): String
}
  • equals() : == 연산자를 오버로딩하는 멤버 함수
  • hashCode() : 객체 고유의 해시코드를 반환하는 멤버 함수
  • toString() : 객체의 내용을 String 타입으로 반환하는 멤버 함수
class Person(val name: String, val age: Int) {
    override fun toString() = "이름:$name 나이:$age"
}

fun main(args: Array<String>) {
    val custom = Person("a", 23)
    println(custom.toString())
}

 

 

3. Nothing 타입

 Nothing은 리턴이라는 행위 자체를 하지 않음을 뜻한다.

fun throwing(): Nothing = throw Exception()

fun main(args: Array<String>) {
    println("start")
    val i: Int = throwing()
    println(i)
}

 위의 예제에서 if 블록은 Int 타입, else 블록이 Nothing 타입이면, if-else는 Int 타입을 따라간다. Nothing 타입은 throw를 표현식으로 쓸 수 있게 하기 위한 장치다.

 

 

4. Nullable 타입과 null

 Nullable이란, null 값을 지정할 수 있는 변수를 뜻한다. 타입 이름 뒤에 ?를 붙이면 변수를 Nullable하게 만들 수 있다.

fun main(args: Array<String>) {
    val str : String? = if (true) "test" else null
}

 "test"는 String, null은 Nothing? 타입이므로, if-else 표현식의 타입은 이 둘이 합쳐진 String?이 된다.

 

 

5. 안전한 호출 연산자 - ?.

 Nullable한 참조 변수의 프로퍼티와 멤버 함수에 접근하려면 . 대신 ?. 연산자를 사용해야 한다.

class Building(var name: String){
    fun print(){
        println("name : $name")
    }
}

fun main(args: Array<String>) {
    var obj: Building? = null
    obj?.print() // print() 함수가 호출되지 않는다.

    obj = Building("백화점")
    obj?.print() // print() 함수 호출된다.
}

 

 

6. Not-null 단정 연산자 - !!

 !! 연산자는 Nullable 타입을 Not-null 타입으로 강제로 캐스팅한다.

class Building(var name: String)

fun main(args: Array<String>) {
    val obj: Building? = null
    obj!!.name = "백화점"
}

 obj는 null이기 때문에 obj!!.name에서 KotlinNullPointerException이 발생한다.

 

 

7. 엘비스 연산자 - ?:

 엘비스 연산자는 왼쪽의 피연산자가 null이 아니면 그 값을 그대로 쓰고, null이면 우측의 피연산자로 대체하는 연산자이다.

fun main(args: Array<String>) {
    val num1: Int? = null
    println(num1 ?: 0) // 0

    val num2: Int? = 15
    println(num2 ?: 0) // 15
}

 

 

8. 스마트 캐스팅

 특정 조건을 만족하는 경우, 컴파일러는 변수의 타입을 다른 타입으로 자동 캐스팅하는 것을 스마트 캐스팅이라 한다.

fun main(args: Array<String>) {
    val num1: Int? = null
    val num2 = 1225

    checkNull(num1)
    checkNull(num2)
}

fun checkNull(any: Any?) {
    if (any == null) {
        println("null이 들어왔습니다.")
        return
    }

    println(any.toString())
}

 if (any == null) 에서 any가 null이면 return 하므로, 아래에서 any?.toString()이 아닌 any.toString()로 호출이 가능하다.

 

 

9. 접근 지정자 (Access Modifier)

  • public : 모든 곳에서 접근 가능, 접근 지정자를 생략하면 기본적으로 public이 된다.
  • internal : 같은 모듈 안에서 접근 가능. (IntelliJ IDEA 모듈, Maven / Gradle 프로젝트 모듈)
  • protected : 클래스 내부와, 서브클래스 안에서만 접근 가능.
  • private : 프로퍼티와 멤버 함수일 경우, 해당 클래스 안에서만 접근 가능하고, 그 외의 경우, 같은 파일 내에서만 접근 가능하다.

 

 

10. 접근 지정자 오버라이딩

 오버라이딩을 통해 protected인 프로퍼티나 멤버 함수의 접근 지정자를 public으로 변경할 수 있다.

open class AAA(protected open val number: Int)

class BBB(number: Int) : AAA(number) {
    public override val number: Int
        get() = super.number
}


fun main(args: Array<String>) {
    val b = BBB(26)
    val a: AAA = b

    println(a.number) // 에러
    println(b.number)
}

 

 

11. 확장 함수 (Extension Function)

 String은 코틀린에 내장된 클래스이기 때문에 원하는대로 멤버 함수를 추가할 수 없다. 이럴 때는 확장 함수를 사용하여, 상속 없이 클래스 외부에서 멤버 함수를 추가할 수 있다. 여기서 함수를 주입할 클래스를 리시버 타입이라고 부른다.

fun String.containNumber(): Boolean { // 문자열에 숫자가 포함되어 있으면 true
    this.forEach {
        if (it in '0'..'9') return true
    }
    return false
}

fun main(args: Array<String>) {
    println("123abc".containNumber()) // true
    println("abc".containNumber()) // false
}

 this를 사용하면 리시버 타입의 프로퍼티나 멤버 함수에 접근할 수 있다.

 

 

12. 객체 선언

 object 키워드를 사용하면 싱글톤 패턴 코드를 더 이상 사용하지 않아도 된다. 프로그램 전체에서 단 하나만 존재하는 객체를 만들 수 있다.

object Person{
    var name: String = ""
    var age: Int = 0
    
    fun print(){
        println("$name $age")
    }
}

fun main(args: Array<String>) {
    Person.name = "leveloper"
    Person.age = 27
    Person.print()
}

 

 

13. 동반자 객체 (Companion Object)

 어떤 클래스의 모든 인스턴스가 공유하는 객체를 만들고 싶을 때 사용한다.

class Person private constructor() {
    companion object {
        fun create(): Person {
            countCreated += 1
            return Person()
        }

        var countCreated = 0
    }
}

fun main(args: Array<String>) {
    val a = Person.create()
    val b = Person.create()
    println(Person.countCreated)
}

 코틀린에는 static 키워드가 존재하지 않는다. static의 효과를 얻고 싶으면 동반자 객체를 사용해야 한다.

 

 

출처 : 초보자를 위한 코틀린 200제 / 엄민석
728x90