•
Kotlin의 모든 클래스에는 공통 슈퍼클래스 Any 가 있다.
•
Any는 슈퍼타입이 선언되지 않은 클래스의 기본 슈퍼클래스이다.
•
Any에는 equals(), hashCode(), toString() 메서드가 있다.
class Example // Implicitly inherits from Any
Kotlin
복사
•
기본적으로 Kotlin 클래스는 final이므로 상속할 수 없어서 상속 가능하게 만들려면 open 키워드를 사용해야 한다.
open class Base // Class is open for inheritance
Kotlin
복사
•
명시적 슈퍼타입을 선언하려면 클래스 헤더의 콜론 뒤에 타입을 적는다.
open class Base(p: Int)
class Derived(p: Int) : Base(p)
Kotlin
복사
•
자식 클래스에 기본 생성자가 있는 경우
◦
자식 클래스는 기본 생성자를 통해 부모 클래스의 생성자를 호출한다.
◦
클래스 헤더가 아닌 보조 생성자에서 부모 클래스의 생성자를 호출해도 된다.
open class Base(val name: String)
class Derived(name: String, val age: Int) : Base(name)
Kotlin
복사
•
자식 클래스에 기본 생성자가 없는 경우
◦
자식 클래스는 보조 생성자를 사용하여 부모 클래스의 생성자를 호출해야 한다.
◦
각 보조 생성자는 super 키워드를 사용하여 부모 클래스의 생성자를 호출하거나 다른 생성자에게 위임해야 한다.
open class View {
constructor(ctx: Context) {
// 초기화 코드
}
}
class MyView : View {
constructor(ctx: Context) : super(ctx) {
// 추가 초기화 코드
}
}
Kotlin
복사
메서드 오버라이딩
•
Kotlin은 오버라이딩 가능한 멤버와 오버라이딩에 대한 명시적인 수정자를 요구한다.
•
부모 클래스의 오버라이딩하려는 메서드에 open 키워드가 붙여야 한다.
•
자식 클래스의 오버라이딩하는 메서드에 override 키워드가 붙여야 한다.
•
오버라이딩을 하기 위해선 클래스에 open 키워드를 붙여야 한다.
open class Shape {
open fun draw() { /*...*/ }
fun fill() { /*...*/ }
}
class Circle() : Shape() {
override fun draw() { /*...*/ }
}
Kotlin
복사
•
override 키워드가 붙은 멤버는 언제든지 하위 클래스에서 재정의될 수 있기 때문에 금지하려면 final 키워드를 붙여야 한다.
open class Rectangle() : Shape() {
final override fun draw() { /*...*/ }
}
Kotlin
복사
프로퍼티 오버라이딩
•
메서드 오버라이딩과 동일한 메커니즘으로 작동한다.
•
부모 클래스에서 선언된 프로퍼티가 자식 클래스에서 다시 선언될 때 override 키워드를 붙여야 하며 타입이 호환돼야 한다.
•
각 선언된 프로퍼티는 초기값을 가지거나 get 메서드를 가지는 프로퍼티로 오버라이딩 할 수 있다.
open class Shape {
open val vertexCount: Int = 0
}
class Rectangle : Shape() {
override val vertexCount = 4
}
Kotlin
복사
•
val 프로퍼티는 var로 오버라이딩 할 수 있지만 그 반대는 불가능하다.
•
val 프로퍼티가 본질적으로 get 메서드를 선언하는 것과 같기 때문에 var로 오버라이딩 하면 추가로 set 메서드도 선언하게 된다.
interface Shape {
val vertexCount: Int
}
class Rectangle(override val vertexCount: Int = 4) : Shape // 항상 4개의 꼭짓점을 가짐
class Polygon : Shape {
override var vertexCount: Int = 0 // 나중에 아무 숫자로든 설정 가능
}
Kotlin
복사
파생 클래스 초기화 순서
•
파생 클래스의 새로운 인스턴스를 생성하는 동안 기본 클래스 초기화는 첫 번째 단계로 수행된다.
•
부모 클래스의 생성자나 초기화 블록에서 open 프로퍼티를 사용하는 것은 예상치 못한 동작을 발생시킬 수 있으므로 피하는 것이 좋다.
open class Base(val name: String) {
init { println("Initializing a base class") }
open val size: Int =
name.length.also { println("Initializing size in the base class: $it") }
}
class Derived(
name: String,
val lastName: String,
) : Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") }) {
init { println("Initializing a derived class") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in the derived class: $it") }
}
Kotlin
복사
1.
Derived 클래스의 생성자가 호출되면 먼저 Base 클래스의 생성자가 호출된다.
2.
Base 생성자의 인수로 전달되는 name 은 name.replaceFirstChar로 변환된다.
3.
Base 클래스의 초기화 블록이 실행된다.
4.
Base 클래스의 size 프로퍼티가 초기화 된다.
5.
Derived 클래스의 초기화 블록이 실행된다.
6.
Derived 클래스의 size 프로퍼티가 초기화 된다.
슈퍼클래스 구현 호출
•
파생 클래스의 코드가 부모 클래스의 함수나 프로퍼티를 호출할 때는 super 키워드를 사용한다.
open class Rectangle {
open fun draw() { println("Drawing a rectangle") }
val borderColor: String get() = "black"
}
class FilledRectangle : Rectangle() {
override fun draw() {
super.draw()
println("Filling the rectangle")
}
val fillColor: String get() = super.borderColor
}
Kotlin
복사
•
내부 클래스에서 외부 클래스의 슈퍼클래스에 접근하려면 외부 클래스 이름으로 한정된 super@Outer 키워드를 사용한다.
class FilledRectangle : Rectangle() {
override fun draw() {
val filler = Filler()
filler.drawAndFill()
}
inner class Filler {
fun fill() { println("Filling") }
fun drawAndFill() {
super@FilledRectangle.draw() // Rectangle의 draw() 구현을 호출
fill()
println("Drawn a filled rectangle with color ${super@FilledRectangle.borderColor}") // Rectangle의 borderColor 접근자 호출
}
}
}
Kotlin
복사
오버라이딩 규칙
•
클래스가 여러 슈퍼클래스로부터 동일한 멤버를 구현하는 경우 반드시 해당 멤버를 오버라이딩하고 상속 받은 구현 중 하나를 사용하여 자신의 구현을 제공해야 한다.
•
상속 받은 구현이 어느 슈퍼클래스로부터 가져온 것인지 나타내기 위해 super<Class> 키워드를 붙여야 한다.
open class Rectangle {
open fun draw() { /* ... */ }
}
interface Polygon {
fun draw() { /* ... */ } // 인터페이스 멤버는 기본적으로 'open'입니다.
}
class Square() : Rectangle(), Polygon {
// 컴파일러는 draw()가 오버라이드 되기를 요구합니다:
override fun draw() {
super<Rectangle>.draw() // Rectangle.draw() 호출
super<Polygon>.draw() // Polygon.draw() 호출
}
}
Kotlin
복사