Kotlin(코틀린) 심화문법 1. 추상 클래스/인터페이스/data 클래스/object 클래스/enum 클래스/sealed 클래스/inner 클래스

차선호·2023년 4월 5일
0

Kotlin

목록 보기
7/8
post-thumbnail

추상 클래스와 인터페이스


abstract class

  • 상속 받을 클래스에서 구현해야 할 프로퍼티 및 메서드를 기술한 클래스

  • abstract 키워드와 함께 선언하며 추상 클래스는 객체 생성 불가

  • 상속을 주기 위해서는 open 키워드를 선언해야 하는데 abstract class는 open이 기본적으로 적용됨

  • java와 달리 추상 프로퍼티를 가질 수 있음

    • 반드시 하위 클래스에서 재정의하여 초기화 해야 함
  • 예제 코드

    // 추상 클래스, 주 생성자에는 비추상 프로퍼티 선언의 매개변수 3개가 있음
    abstract class Vehicle(val name: String, val color: String, val weight: Double) {
        // 추상 프로퍼티 (반드시 하위 클래스에서 재정의해 초기화해야 함) -> 자바와 차이점
        abstract var maxSpeed: Double
        // 일반 프로퍼티 (초기 값인 상태를 저장할 수 있음)
        var year = "2018"
        // 추상 메서드 (반드시 하위 클래스에서 구현해야 함)
        abstract fun start()
        abstract fun stop()
        // 일반 메서드
        fun displaySpecs() {
            println("Name: $name, Color: $color, Weight: $weight, Year: $year, Max Speed: $maxSpeed") }
    }
    class Car(name: String, color: String, weight: Double, override var maxSpeed: Double) : Vehicle(name, color, weight) {
        override fun start() {
            println("Car Started") // 코드의 구현
        }
        override fun stop() {
            println("Car Stopped") // 코드의 구현
        }
    }
    class Motorcycle(name: String, color: String, weight: Double, override var maxSpeed: Double) : Vehicle(name, color, weight) {
        override fun start() {
            println("Bike Started") // 코드의 구현
        }
        override fun stop() {
            println("Bike Stopped") // 코드의 구현
        }
    }
    fun main() {
        val car = Car("SuperMatiz", "yellow", 1110.0, 270.0)
        val motor = Motorcycle("DreamBike", "red", 173.0, 100.0)
        car.year = "2013"
        car.displaySpecs()
        car.start()
        motor.displaySpecs()
        motor.start()
    }

interface

  • 자바와 동일하게 구현부가 없는 method + default method의 집합

    • default 키워드는 따로 없음
  • 상속을 주기 위해 만들어진 클래스로 별도의 open 키워드는 필요 없음

  • 상속 받는 interface에서 동일한 function이 있다면 반드시 구현해야 함

  • 예제 코드

    interface Clickable {
        fun click()
        fun showOff(){
            println("Clickable.showOff")
        }
    }
    interface Focusable{
        fun showOff(){
            println("Focusable.showOff")
        }
    }
    class Button : Clickable, Focusable {
        override fun click() {
            println("Button.click")
        }
        //showOff는 두 슈퍼에 모두 존재하므로, 동일하게 애매함을 없애기 위해서 반드시 선언.
        //super에 선언된 fun을 호출할때는 super<Clickable>.showOff()
        //java에서는 Clickable.super.showOff();
        override fun showOff() {
            println("Button.showOff")
        }
    }
    
    fun main() {
        var button = Button()
        button.click()
        button.showOff()
    }




data class


특징

  • data class 키워드로 선언해서 사용

  • 변수나 상수를 선언할 수 있음 (구분은 쉼표( , ) 로)

  • 프로퍼티를 일반 클래스 내의 프로퍼티를 기준으로 생성자가 만들어짐

  • DTO(Data Transfer Object)를 다룰 때 유용

  • 자바와 다르게 getter, setter 만들 필요가 없고 초기화도 필요 없이 선언하기만 하면 끝

일반 클래스 vs data class

  • 일반 클래스와 달리 소괄호로 프로퍼티를 선언하면 끝

  • 자동으로 파라미터 생성자, toString( ), equals( ), hashCoode 등 제공

  • { } 열어서 function 추가도 가능

  • 예시 코드

    //일반 클래스
    class Person20(var name: String) {
        private var type: String = ""
        private var age: Int = 0
    
        constructor(name: String, type: String, age: Int) : this(name) {
            this.type = type
            this.age = age
        }
    
        fun myMbTi() {
            println("my name is $name and type is $type")
        }
    }
    //data clas
    data class PersonData(val name: String, val type: String, var num: Int, var own: Boolean)
    
    fun main(args: Array<String>) {
    
        val person20 = Person20("김싸피", "ENFP", 23)
        person20.myMbTi()
    
        val person = PersonData("김싸피", "ENFP", 23, true)
        println(person)
    
        if (person.own)
            println("my name is  ${person.name}")
        else
            println("i'm not human being")
    
    }




object class


특징

  • object 키워드로 선언

    • class 키워드 위치에 object 키워드 선언 → 싱글톤 클래스가 됨
  • 생성자를 갖지 않음

    • 생성자가 private로 선언되므로 가질 수 없음 → 싱글톤
  • 어느 클래스, 함수에서든 별도의 객체화 과정 없이 접근 가능

  • 프로그램이 실행되는 동안 저장된 데이터는 손실되지 않고, 프로그램이 종료되면 소멸

  • 위 특징 덕분에 안드로이드에서는 액티비티, 프래그먼트 구분하지 않고 데이터 전달 가능

  • anonymous nested class를 생성할 때 사용

    • 익명 객체 = 재사용 없는 객체 = 일회성 객체
  • 예제 코드

    object PersonObject {
        var name: String = ""
        var type: String = ""
        var age: Int = 0
    
        fun myType() {
            println("my name is $name and type is $type age is $age")
        }
    }
    
    fun main() {
        val name = "samsung"
        val type = "ENFP"
        val age = 23
    
        PersonObject.name = name
        PersonObject.type = type
        PersonObject.age = age
        PersonObject.myType()
        println("${PersonObject.name} and ${PersonObject.type} and ${PersonObject.age}")
    }



enum class


특징

  • java와 동일한 열거형

  • [클래스 이름.name] 으로 이름 값 접근 가능

  • [클래스 이름.ordinal] 으로 해당 값이 몇 번째에 기록되어 있는지 순서 값 접근 가능

  • 인자가 있는 열거형 클래스인 경우 열거 값들을 표현하는 방식을 다채롭게 할 수 있음

인자 없는 열거형 클래스

  • 별도의 인자가 없는 가장 기본적인 형태의 열거형 클래스
    enum class ExHandsome {
        EX, LOVE, PEACE
    }
    
    fun main() {
        val exEnum: ExHandsome = ExHandsome.LOVE
        println("${exEnum.name} ... ${exEnum.ordinal}")
    
        val exEnum2: Array<ExHandsome> = ExHandsome.values()
    
        for (i in exEnum2.indices) {
            println(exEnum2[i].name)
        }
    
    }

인자 있는 열거형 클래스

enum class Human(val age: Int) {
    KIM(25), CHOI(21)
}

fun main() {
    val human: Human = Human.KIM
    println("${human.name}, ${human.age}, ${human.ordinal}")

}



sealed class


특징

  • 부모 클래스의 상속을 받는 자식 클래스의 종류를 제한하는 클래스

  • sealed class에 정의된 하위 클래스 외의 다른 하위 클래스는 존재하지 않는다는 것을 컴파일러에게 알려줌

  • sealed class 키워드를 선언해서 사용

  • sealed class도 추상 클래스로 객체 생성 불가

  • sealed class와 그 하위 클래스는 동일한 파일에 정의되어야 함.

  • 하위 클래스는 class, data class, object class로 정의 가능

  • 예시 코드

    sealed class Color {
        object Red : Color()
        object Green : Color()
        object Blue : Color()
    }
    fun main() {
        val color: Color = Color.Red
    	
    		val font = when (color) {
            is Color.Red -> "Noto Sans"
            is Color.Green -> "Open Sans"
            is Color.Blue -> "sans-serif"
            // No error!
        }
        println("결정된 font는 : $font")
    		
    		val font2 = when (color) {
            is Color.Red -> "Noto Sans"
            is Color.Green -> "Open Sans"
            is Color.Blue -> "sans-serif"
        }
        println("결정된 font는 : $font")
    }

sealed class vs enum

  • 공통점

    • 둘 다 타입을 제한할 때 사용
  • 차이점

    • enum은 하나의 객체만 생성 가능

    • sealed class는 여러 개의 객체 생성 가능

  • 예시 코드

    sealed class Expr
    
    data class Const(val number: Double) : Expr()
    data class Sum(val e1: Expr, val e2: Expr) : Expr()
    object NotANumber : Expr()
    
    fun eval(expr: Expr): Double = when (expr) {
        is Const -> {
            expr.number
        }
        is Sum -> {
            eval(expr.e1) + eval(expr.e2)
        }
        is NotANumber -> {
            Double.NaN
        }
    }
    
    fun main() {
        val num1 = Const(10.0)
        val num2 = Const(20.0)
        val sum = Sum(num1, num2)
        val result = eval(sum)
        println("result : $result")  //30.0
    
    }




inner class


특징

  • 자바에서는 클래스 안에 클래스를 정의하면 자동으로 내부 클래스가 되었지만 코틀린에서는 클래스 안에 클래스 선언하면 그냥 중첩 클래스가 됨

  • 내부 클래스로 만드려면 inner 키워드로 선언해야 함

  • 내부 클래스는 기본적으로 외부 클래스를 참조 할 수 있지만, 중첩 클래스는 선언이 클래스 내부에 있을 뿐 외부 클래스의 member에 접근 불가

Nested class vs Inner class

// nested class중첩 클래스
classOuter {
private valbar: Int = 1

classNested {
// nested class는 외부 클래스 멤버 참조 불가 (자바에선 가능했다.)
        //그냥 안에 있는 클래스 정도라 생각해라
// fun foo() = bar
funfoo() = 2
    }
}

// inner class내부 클래스
classOuterInner {
private valbar: Int = 1

inner classInner {
funfoo() = bar
//        fun foo() = this@OuterInner.bar
}
}

funmain() {

valdemo = Outer.Nested().foo()
valdemo2 = OuterInner().Inner().foo()
println(demo)// 2
println(demo2)// 1
}

가시성 지시자

  • 가시성 지시자(Visibility modifiers)를 통해서 외부 접근 범위를 정할 수 있음

    • private

      • 외부에서 접근 불가
    • protected

      • 상속 관계에 있을 때만 외부에서 접근 가능
    • internal

      • 같은 모듈 내에서 접근 가능
    • public

      • 어디서든 접근 가능(기본값)
profile
dkssud!

0개의 댓글