코진남

[Kotlin] interface ,open, final, abstract 본문

BackEnd/코틀린

[Kotlin] interface ,open, final, abstract

woojin126 2022. 6. 30. 11:16

 

인터페이스

코틀린에서는 자바와는달리 override 변경자를 꼭 사용해야 한다. override 변경자는 실수로 상위 클래스의 메서드를 오버라이드하는 경우를 방지해준다. 인터페이스 메서드도 디폴트 구현을 제공할 수 있따. 그런 경우 메서드 앞에 default를 붙여야하는 자바와는 달리 코틀린에서 특별한 키워드로 꾸밀 필요없다. 그냥 메서드 본문을 메서드 시그니처 뒤에 추가하면 된다. 

 

interface Clickable {
	fun click()
    fun showOff() = println("I'm clickable!")
}

이 인터페이스를 구현하는 클래스는 clickq에 대한 구현을 제공해야 한다. 반면 showOff 메서드의 경우 새로운 동작을 정의할 수 있고,
그냥 정의를 생략해서 디폴트 구현을 사용할 수 있다.

interface Focusable {
	fun setFocus(b: Boolean) = 
    println(I ${if (b) "got" else "lost"} focus.")
    
    fun showOff() = println("I'm focusable!)
}

Focusable과 같이 한클래스에서 두인터페이스를 함께 구현하면 어떻게될까? 두 인터페이스 모두 디폴트 구현이 들어있는 showOff 메서드가 있다. 어느쪽 showOff 메서드가 선택될까. 답은 둘다 아니다. (오류발생)

 

하지만 코틀린 컴파일러는 두 메서드를 하위 클래스에 직접 구현하게 강제한다. (괄호안에 타입을 지정한다.)

class Button : Clickable, Focusable {
	ovveride fun click() = println("I was clicked")
    ovveride fun showOff() {
    	super<Clickable>.showOff()
        super<Focusable>.showOff()
    }
}

Button 클래스는 이제 두 인터페이스를 구현한다. Button은 상속한 두 상위 타입의 showOff() 메서드를 호출하는 방식으로 구현한다.

 

호출해보자

fun main(args: Array<String>) {
	val button = Button()
    button.showOff()
    button.setFocus(true)
    button.click()
}

 

 

open 변경자

자바에서 final로 명시적으로 상속을 금지하지 않는 모든 클래스를 다른 클래스가 상속할 수 있다. 이렇게 기본적으로 상속이 가능하면 편리한 경우도 있지만, 문제가 더 많다.

취약 기반 클래스 라는 문제는 하위 클래스가 기반 클래스에 대해 가졌던 가정이 기반 클래스(부모)를 변경함으로써 깨져버린 경우가 생긴다. 하위클래스는 기반 클래스를 작성한 사람의 의도와는 다른 방식으로 메서드를 오버라이드할 위험성이 있다.

 

"하위 클래스에서 오버라이드하게 의도된 클래스와 메서드가 아니라면 모두 final로 만드는게 좋다. "

 

코틀린도 마찬가지 철학을 따른다. 자바의 클래스와 메서드는 기본적으로 상속에 열려있지만 코틀린의 클래스와 메서드는 기본적으로 final이다.

어떤 클래스의 상속을 허용하려면 클래스 앞에 open 변경자를 붙여야한다. 그와 더불어 오버라이드를 허용하고 싶은 메서드나 프로퍼티의 앞에도 open 변경자를 붙여야한다.

 

open class RichButton: Clickable { <- 이클래스는 열려있다. 다른 클래스가 이클래스를 상속할 수 있다.
	fun disable() {} <- 이 함수는 파이널이다. 하위 클래스가 이 메서드를 오버라이드 할 수 있다.
    open fun animate() {}  <- 함수는 열려있다. 하위 클래스에서 이메서드를 오버라이드해도 된다. 
    override fun click() {} <- 이 함수는 (상위 클래스에서 선언된) 열려있는 메서드를 오버라이드한다. 오버라이드한 메서드는 기본적으로 열려있다.
}

 

기반 클래스나 인터페이스의 멤버를 오버라이드하는 경우 그 메서드는 기본적으로 열려있다. 오버라이드하는 메서드의 구현을 하위 클래스에서 오버라이드하지 못하게 금지하려면 메서드 앞에 final을 명시하자.

open class RichButton : Clickable {
	final override fun click() {} <- 여기있는 "final"을 쓸대 없이 붙는 중복이 아니다. "final"이 없는 "override"는 메서드나 프로퍼티는 기본적으로 열려잇따.
}

 

한번 final로 변경한 클릭메서드를 다른클래스를 만들어 오버라이드를 하려고하면 빨간 밑줄이 나온다.

 

 

Abstract 변경자

abstract로 선언한 추상 클래스는 인스턴스화할 수 없다. 추상 클래스에는 구현이 없는 추상 멤버가 있기 때문에 하위 클래스에서 그 추상 멤버를 오버라이드해야만 하는게 보통이다. 추상 멤버는 항상 열려있다. 따라서 추상맴버 앞에 open 변경자를 명시할 필요 없다.

 

abstract class Animated { <- 이 클래스는 추상클래스다. 이클래스의 인스턴스를 만들 수 없다.
	abstract fun animate() <- 이함수는 추상 함수다.이 함수에는 구현이 없다. 하위클래스에서는 이 함수를 반드시 오버라이드 해야한다.
    
    open fun stopAnimating(){} <- 추상 클래스에 속했더라도 비추상 함수는 기본적으로 파이널이지만 원한다면 open으로 오버라이드를 허용할 수있다.
     		                   (이것은 강제가아닌 원하면 오버라이드할 수 있고, 안할 수 있다.
    
    fun animateTwice() {}
}

 

 

아래는 위의 추상클래스를 오버라이드. 하지만 위의 코드 3번째 메서드는 기본 final로 지정되있어 오버라이드 불가능

class FiFi: Animated() {
    override fun animate() {
        TODO("Not yet implemented")
    }

    override fun openAni() {
        super.openAni()
    }

}

 

 

'BackEnd > 코틀린' 카테고리의 다른 글

[Kotlin] 코틀린 위임 by  (0) 2022.08.20
[Kotlin] 내부 클래스 중첩 클래스  (0) 2022.07.30
코틀린 타입추론과 함수 4편  (0) 2022.04.16
코틀린 형변환과 배열 3편  (0) 2022.04.16
코틀린 변수와 자료형 2편  (0) 2022.04.16