[Kotlin] interface 와 open, final, abstract

developer-shkim·2021년 6월 30일
1

Kotlin

목록 보기
3/4
post-thumbnail

interace 와 abstract 에 대한 개념이 잘 구분되지 않아서 정리해보았습니다!

interface

개념

  • 추상 메소드, 구현 있는 메소드 모두 정의할 수 있다.
  • 아무런 상태(필드)도 들어갈 수 없다.
  • 클래스 이름 뒤에 콜론(:) 붙이고 이름 적는 것으로 인터페이스 구현과 클래스 확장을 처리한다.
interface Clickable {
    fun click()
}

class Button : Clickable {
    override fun click() = println("I was clicked")
}

default 메소드

interface Clickable {
   fun click()    // 일반 메소드 선언
   fun showOff() = println("I'm clickable!")    // 디폴트 구현

interface Focusable 
   fun setFocus(b: Boolean) =
       println("I ${if (b) "got" else "lost"} focus.")
   fun showOff() = println("I'm focusable!")
}
  • 인터페이스 메소드도 default 구현을 제공할 수 있다.
  • 자바 8 에서 메소드 앞에 default 를 붙여야 하는 것과 달리 키워드를 추가하지 않아도 된다.
  • 인터페이스를 구현하는 클래스는 click 에 대한 구현을 제공해야 한다.
  • showOff 메소드의 경우, 새로운 동작을 정의할 수도 있고, 생략해서 구현을 사용할 수도 있다.
  • 한 클래스에서 두 인터페이스를 함께 구현하면 컴파일 에러
    • The class 'Button' must override public open fun showOff() because it inherits many implementations of it.

implement

class Button : Clickable, Focusable {
    override fun click () = println("I was clicked")

    // 2개 이상 default 메소드 -> 명시적으로 새로운 구현 제공
    override fun showOff() {
        // super<상위타입이름> 로 어떤 상위타입 멤버 메소드 호출할지 지정 가능 
        super<Clickable>.showOff()
        super<Focusable>.showOff()
    }
}

fun main() {
    val button = Button()
    button.showOff()
    /*
        I'm clickable!
        I'm focusable! 출력
    */
    button.setFocus(true)    // I got focus.
    button.click()    // I was clicked.
}
  • 상위타입 멤버 메소드 호출 지정
    • 자바에서는 Clickable.super.showOff()
    • 코틀린에서는 super.showOff()
  • Button 클래스는 Focusable 인터페이스 안에 선언된 setFoucs 구현 자동 상속

자바에서 코틀린 메소드가 있는 인터페이스 구현

  • 코틀린은 인터페이스의 default 메소드 지원 X
  • 인터페이스와 정적 메소드로 들어 있는 클래스를 조합해 구현
  • 인터페이스와 함께 생성되는 클래스에는 모든 default 메소드 구현이 정적 메소드로 들어간다.
  • 자바 클래스에서 상속해 구현하고 싶다면, default 메소드를 포함하는 모든 메소드에 대한 본문을 작성해야 한다.
  • 결론: 자바에서는 코틀린의 default 메소드 구현에 의존할 수 없다.

override

  • 자바의 @override 애노테이션과 비슷하다.
  • 자바와 달리 override 변경자를 꼭 사용해야 한다.
  • 상위 클래스나 상위 인터페이스에 있는 프로퍼티나 메소드를 오버라이드 한다는 의미
  • 상위 클래스의 메소드와 시그니처가 같은 메소드를 하위 클래스에서 선언하는 경우, 컴파일 에러 발생한다.
    • 실수로 오버라이드 하는 경우를 방지한다.
    • 상위 클래스 메소드와 시그니처가 같은 메소드를 우연히 하위 클래스에서 선언하는 경우 컴파일 X
    • override 붙이거나 메소드 이름을 바꿔야만 한다.

상속 제어 변경자(open, final, abstract)

개념

  • 코틀린의 클래스와 메소드는 기본적으로 final
  • 오버라이드 허용하고 싶은 메소드나 프로퍼티 앞에 open 붙여야 한다.
  • 클래스의 기본적인 상태를 final 로 함으로써 얻을 수 있는 큰 이익은 스마트 캐스트가 가능하다는 점이다.
    • 클래스 프로퍼티의 경우 val 이면서 커스텀 접근자가 없는 경우에만 스마트 캐스트를 쓸 수 있다는 의미이다.
    • 프로퍼티는 기본적으로 final 이기 때문에 고민할 필요없이 대부분 스마트 캐스트에 활용할 수 있다.

자바에서는...

  • final 이 아닌 모든 클래스를 다른 클래스가 상속 가능
  • 편리하지만 '취약한 기반 클래스(fragile base class)' 문제 발생할수 있다.
    • 하위 클래스가 기반 클래스에 대해 가졌던 가정이 기반 클래스를 변경함으로써 깨져버린 경우 발생
    • 모든 하위 클래스 분석하는 것은 불가능
    • 기반 클래스 변경하는 경우 하위 클래스 동작이 예기치 않게 바뀔 수도 있다는 면에서 취약
  • "상속을 위한 설계와 문서를 갖추거나, 그럴 수 없다면 상속을 금지하라" ⌜Effective Java⌟(조슈아 블로크, 2008)
    • 하위 클래스에서 오버라이드하게 의도된 클래스와 메소드가 아니라면 모두 final 로 만들라는 의미이다.
open class RichButton : Clickable {
// 이 클래스는 열려있다. 다른 클래스가 이 클래스 상속할 수 있다.
    fun disable() { }    // final, 오버라이드 X
    open fun animate() { }    // 오버라이드 O
    override fun click() { }    // 오버라이드 O, 금지하려면 final 명시

abstract

  • 추상 클래스는 인스턴스화할 수 없다.
  • 구현이 없는 추상 멤버가 있기 때문에 하위 클래스에서 그 추상 멤버를 오버라이드 해야만 한다.
  • 추상 멤버 앞에 open 변경자 명시할 필요없다.
abstract class Animated {
// 추상 클래스로, 인스턴스 만들 수 있다.
    abstract fun animate()
    // 추상 함수, 구현이 없다.
    // 하위 클래스에서는 반드시 오버라이드 해야 한다.

    open fun stopAnimating() { 
    }
    // 추상 클래스에 속했더라도 비추상 함수는 final 이지만
    // open 으로 오버라이드 허용할 수 있다.

    fun animateTwice() {
    }
}

interface 에서는 ...

  • 인터페이스 멤버의 경우 상속 제어 변경자(final, open, abstract) 사용하지 않는다.
  • 항상 열려 있으며 final 로 변경할 수 없다.
  • 인터페이스 멤버에게 본문이 없으면 자동으로 추상 멤버가 되어서 따로 abstract 키워드 추가할 필요가 없다.
변경자변경자 붙은 멤버는설명
final오버라이드 X클래스 멤버 기본 변경자
open오버라이드 O반드시 open 명시 -> 오버라이드 가능
abstract반드시 오버라이드추상 클래스 멤버에만 변경자 붙일 수 있고, 추상 멤버에는 구현이 있으면 안 된다.
override상위 클래스나 상위 인스턴스의 멤버를 오버라이드 하는 중오버라이드 하는 멤버는 기본적으로 열려있고, 하위 클래스 오버라이드 금지하려면 final 명시해야 한다.
profile
기록하고 기억하자!

0개의 댓글