코틀린은 자바에서 빈번하게 일어나는 상속 오남용을 막기 위해 모든 클래스가 기본적으로 상속 불가(final) 상태로 잠겨 있습니다. 부모 클래스가 되려면 명시적으로 open 키워드를 붙여 상속을 허락해야 합니다.
반면 인터페이스(Interface)는 자바 8과 유사하게 구현체가 없는 추상 메서드뿐만 아니라, 본문이 있는 디폴트 메서드와 추상 프로퍼티까지 가질 수 있어 매우 유연한 설계가 가능합니다.
💡 핵심 비유: 굳게 닫힌 문과 허락된 열쇠 (open)
자바는 아무 클래스나 문이 열려 있어서 무분별한 상속(무단침입)이 일어났습니다.
코틀린은 모든 클래스의 문이 final이라는 자물쇠로 잠겨 있습니다. 누군가 나를 상속하게 놔두려면 반드시 내 이름 앞에 open (열쇠)을 걸어두어야 합니다.
🧬 코틀린의 상속 다이어그램
📊 Java vs Kotlin 상속 키워드 비교
동작
Java 키워드
Kotlin 키워드
클래스 상속
extends
콜론( : ) 사용
인터페이스 구현
implements
동일하게 콜론( : ) 사용
메서드 재정의
@Override (어노테이션)
override (키워드 강제)
// 1. 인터페이스 정의
// 자바와 달리 프로퍼티(val maxSpeed)를 추상화할 수 있습니다.
interface Flyable {
val maxSpeed: Int
fun fly() // 추상 메서드
// 본문이 있는 디폴트 메서드도 인터페이스에 작성 가능
fun landing() {
println("안전하게 착륙합니다.")
}
}
// 2. 상속을 허용하는 open 클래스
// 코틀린 클래스는 기본이 final이므로, 부모가 되려면 반드시 'open'을 써야 합니다.
// 메서드 역시 오버라이딩을 허용하려면 'open'을 붙여야 합니다.
open class Animal(val name: String) {
open fun makeSound() {
println("$name 가 소리를 냅니다.")
}
}
// 3. 상속과 인터페이스 다중 구현
// 자바의 extends, implements 대신 콜론( : ) 하나로 통일합니다.
// Animal은 클래스이므로 생성자()를 호출해야 하고, Flyable은 인터페이스이므로 이름만 적습니다.
class Bird(name: String, override val maxSpeed: Int) : Animal(name), Flyable {
// 자바의 @Override 어노테이션 대신, 코틀린은 override라는 '키워드'를 강제합니다.
override fun makeSound() {
println("짹짹!")
}
override fun fly() {
println("$name 가 최대 속도 $maxSpeed 로 하늘을 납니다!")
}
}
fun main() {
val sparrow = Bird("참새", 50)
sparrow.makeSound()
sparrow.fly()
sparrow.landing() // 인터페이스에 구현된 디폴트 메서드 호출
}