인터페이스와 상속 관계

2018, Jun 14    

인터페이스 정의

java와 마찬가지로 interface를 사용한다.


interface Clickable {
  fun click()     //추상 메소드
}

인터페이스 구현하기 위해서는 클래스 이름 뒤에 콜론(:)을 붙이고 인터페이스를 붙인다. 특이한 점은 상속(extends)도 똑같은 방법으로 이루어진다. 따라서 콜론(:)을 통해 인터페이스와 확장이 동시에 이루어진다.


class Button : Clickable {
  //override 변경자로 오버로딩 한다는 것을 표시한다.
    override fun click() = println("구현체")
}

>>> Button().click()
구현체
  • 변경자 override는 자바의 @override와 비슷한 것으로 인터페이스에 있는 프로퍼티나 메소드를 오버라이드한다는 표시다.
  • 자바와 달리 코틀린에서는 override변경자를 꼭 사용해야 한다. 이는 실수로 상위 클래스의 메소드를 오버라이드 하는 것을 방지해준다.
  • 자바와 마찬가지로 인터페이스는 복수로 구현할 수 있지만, 클래스는 오직 하나만 확장할 수 있다.
  • 코틀린에서는 인터페이스에서도 구현이 있는 메소드도 정의 할수 있다.(java8의 default함수와 비슷)

interface MyInterface {
    fun printWelcome() {
        println("welcome")
    }
}

class MyClass : MyInterface {

}

>>> MyClass().printWelcome()
welcome

이렇게 구현체를 가진 메소드와 같은 이름을 가진 다른 인터페이스를 추가로 구현한다면 어떻게 될까?
이런경우 구현체 class에서는 해당 메소드를 override해야 한다 syntax오류가 발생한다.


interface MyInterface {
    fun printWelcome() {
        println("welcome")
    }
}

interface SameMethodInterface {
    fun printWelcome() {
        println("Hello")
    }
}

class MyClass2 : MyInterface, SameMethodInterface { //<-- syntax 오류 발생

}

------------------------------------------------------------
error: class 'MyClass2' must override public open fun printWelcome(): Unit defined in Line_68.MyInterface because it inherits multiple interface methods of it

상위 타입의 멤버 메소드를 호출 할시에는 super<상위타입> 로 구분하여 어떤 상위 타입의 메소드를 실행할지 지정 할 수 있다.

interface SameMethodInterface {
    fun printWelcome() {
        println("Hello")
    }
}

class MyClass : MyInterface {

}

class MyClass2 : MyInterface, SameMethodInterface {
    override fun printWelcome() {
        super<MyInterface>.printWelcome()

        super<SameMethodInterface>.printWelcome()
    }
}

>>> MyClass2().printWelcome()
welcome
Hello

기본적으로 닫혀 있는 class


코틀린의 클래스와 메소드는 기본적으로 final이다.

  • 취약한 기반 클래스fragile base class
    기본적으로 클래스와 메소드가 상속에 대해 열려 있는 자바에서는 상위 클래스를 변경할시 예기치 않은 문제가 발생할 수 있는 위험이 있다.
  • 코틀린에서는 이런 문제를 차단하기 위해서 클래스와 메소드를 기본적으로 final로 설정해 두고 상속을 허용하는 경우에만
    open 변경자를 붙이도록 하고 있다.

//상속에 열려있는 클래스
open class OpenMyClass : MyInterface {

    fun finalMethod() {}  //<-- final함수, 하위 클래스가 이 메소드를 오버라이드 할 수 없다.

    open fun openMethod() {}  //<-- open함수, 하위 클래스가 이 메소드를 오버라이드 할수 있다.

    override fun printWelcome() = println("welcome to kotlin") //<-- open함수, override한 메소드는 기본적으로 열려 있다.
}
  • override 메소드는 기본적으로 상속에 열려 있다. 이것을 금지 하고 싶다면 final로 선언하면 된다.
    final override fun printWelcome() = println("welcome to kotlin")

추상 클래스 정의


  • 자바처럼 코틀린에서도 클래스를 abstract로 선언한다.
  • abstract로 선언한 추상 클래스는 인스턴스화할 수 없다.
  • 추상 클래스는 상속에 항상 열려있다.

abstract class Animated {
  abstract fun animate()        //<-- 반드시 구현해야 할 추상 메소드
  fun animateTwice() {}         //override 불가
  open fun stopAnimating() {}   //override 가능
}
  • 추상 클래스내에 abstract 함수는 반드시 override 해야한다.
  • 추상 클래스에 속해 있다 하더라도 abstract 함수가 아니 일반 함수는 override를 허용하지 않는다.

class childClass : Animated() {
    override fun animate() = print("animate")               //<-- override하지 않으면 에러 발생
    override fun stopAnimating() = print("can overriding")
    override fun animateTwice() {}                          //<-- sytax Error
}