Java에는 final이라는 키워드가 있다. final로 선언된 클래스와 메소드는 기본적으로 상속과 오버로드가 제한된다. 즉, 자식 클래스에서 이 클래스나 메소드를 재정의하려 할 때 컴파일 에러를 발생시키게 된다. final로 선언한다는 의미는 명시적으로 Override Method를 제한하고 싶을 때 사용할 수 있다.
Kotlin은 어떨까? Kotlin의 클래스와 메소드는 기본적으로 final이다. 하지만, 우리는 다양한 이유로 클래스나 메소드를 상속하여 개발해야 하는 상황이 존재한다. 이를 위해, Kotlin은 상속에 사용되는 몇가지 키워드를 제공하고 있다.
1. open class
open class Shape
class Rectangle(var height: Double, var length: Double): Shape() {
var perimeter = (height + length) * 2
}
위 코드는 Shape라는 클래스를 상속하여 Rectangle 클래스를 구현하고 있다. 상속을 허용하기 위해 open이라는 키워드를 붙인 것을 확인할 수 있다.
open class Sample {
open fun a() { // override 가능
print("Can override?")
}
fun b() { } // override 불가능
}
어떤 클래스가 Sample을 상속한다고 가정해 보자. 그렇다면 그 클래스는 Sample이 상속 가능하게 구현한 a() 메소드도 함께 override할 수 있을 것이다. 하지만, b() 메소드는 override할 수 없다. 기본적으로 final이기 때문이다.
여기서 우리는 open키워드가 붙은 메소드가 final 클래스의 멤버에 추가될 경우 마찬가지로 무의미하다는 것을 함께 알 수 있다.
open class Rectangle() : Shape() {
final override fun draw() { /* ... */ }
}
위 코드는 Shape에서 구현한 draw 메소드를 override한 Rectangle 클래스이다. 마찬가지로 Rectangle도 상속을 허용하기 위해 open으로 선언한 것을 볼 수 있다.
우리는 어떤 경우에서 open class의 멤버인 open fun의 override를 제한할 수도 있다. 이 경우 해당 메소드에 final 키워드를 붙이면 된다. 위 코드에서는 Rectangle을 상속하는 클래스는 draw()를 override할 수 없게 된다.
open class Shape {
open val vertexCount: Int = 0,
open val x: Int get { /* ... */ }
}
class Rectangle(override val x: Int) : Shape() {
override val vertexCount = 4
....
}
open은 마찬가지로 클래스의 멤버 프로퍼티에도 적용할 수 있다. 위 코드처럼 val 프로퍼티에 open 키워드를 붙이게 되면 마찬가지로 상속할 수 있게 된다.
지금 까지 open 키워드에 대해 알아보았다. open은 상속을 허용하게 하는 키워드이다. 이 말은 단지, 상속을 허용한다는 의미이지 반드시 override해야 한다는 뜻은 아니다. 즉, 선택적으로 override할 수 있다. 또한, open fun일 경우에는 반드시 바디를 가져야 한다.
2. abstract class
Java와 동일하게 Kotlin에서도 클래스 내부의 멤버에 대해 abstract하게 선언할 수 있다. 또한, abstract하게 선언된 멤버들은 구현이 없다. 여기서 open과의 차이점을 알 수 있는데, 메소드의 경우 abstract로 선언하게 되면 바디를 갖지 않고 해당 클래스를 상속하는 자식 클래스에서 바디를 구현해야 한다.
abstract class Polygon {
abstract fun draw()
}
class Rectangle :Polygon() {
override fun draw() {
// Draw Rectangle
}
}
위 코드에서 볼 수 있듯이 Polygon 클래스의 멤버 함수인 draw는 바디를 갖고있지 않다. 단순히 선언만 하게 되는데, Polygon을 상속하는 Rectangle에서 draw에 대한 구현을 하는 것을 볼 수 있다.
open class를 추가하여 확장할 수도 있다.
open class Polygon {
open fun draw() {
// Some default polygon drawing method
}
}
abstract fun WildShape : Polygon() {
abstract override fun draw()
}
위 코드처럼 Polygon에 선언된 draw 메소드를 WildShape에서 재정의하고 abstract로 확장한 후, 특정 클래스에서 WildShape를 상속하게 된다면 Polygon에 정의된 default 구현 대신 자체적으로 draw를 override한 메소드를 사용하게 된다.
3. 정리
open과 abstract에 대해 알아보았다. 아래와 같이 정리할 수 있다.
1. Kotlin에서 상속을 위해 open과 abstract를 사용한다.
2. open fun은 반드시 바디를 구현해야 한다.
3. open class의 멤버는 기본적으로 open이다.
4. abstract fun은 바디를 갖지 않기 때문에 반드시 override해 구현해야 한다.
References
'Kotlin' 카테고리의 다른 글
(Kotlin) runCatching, Result (0) | 2022.10.28 |
---|---|
(Kotlin) sealed class (0) | 2022.07.27 |
(Kotlin) Class 정의 (0) | 2021.10.04 |
객체 지향 프로그래밍 (OOP) (0) | 2021.10.04 |
(Kotlin) Scope 함수 (0) | 2021.09.09 |