7. 상속 - Inheritance
1. 상속 - 최상위 클래스 Any
- 클래스에 상위타입을 선언하지 않으면 Any가 상속됨
- 코틀린의 최상위 클래스는 Any이다.
class Test1 // 암시적인 Any상속
class Test2 : Any() // 명시적인 Any상속
// java의 extend 대신 콜론(:) 을 쓴다.
- Any는 java.lang.Object와는 다른 클래스이다.
- equals(), hashCode(), toString() 만 있다.
package kotlin
public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}
2. 상속 - 특징
- 명시적으로 상위타입을 선언하려면, 클래스 해더의 콜론 뒤에 상위타입을 선언하면 됨.
- 파생클래스에 기본생성자가 있으면 파생클래스의 기본생성자에서 상위타입의 생성자를 호출해서 초기화 할 수 있다.
//상속을 해줄 클래스가 open을해주어야 다른 클래스가 상속을 받을 수 있다.
open class AA(x: Int)
// 파생클래스 (상속받을 클래스)
// 상속받을 클래스 : 상위타입
// 상속받을 클래스에 기본생성자가 있으면 상위타입의 생성자를 호출해서 초기화 할 수 있음.
class BB(x: Int) : AA(x)
- 파생클래스에 기본생성자가 없으면,
- 각각의 보조생성자에서 상위타입 super 키워드를 이용해서 초기화 해주어야 하거나,
- 다른 생성자에게 상위타입 초기화를 할 수 있게 위임하여야 한다.
// 파생클래스에 기본생성자가 없다.
class Myview : View {
constructor() : super(1) // 1. super를 이용한 상위타입을 초기화
constructor(x: Int) : this() // 2. 위에 생성자에게 상위타입 초기화하도록 위임
constructor(x: Int, y: Int) : super(x,y) // 1.super를 이용한 상위타입 초기화
}
3. 상속 - open
- open class는 다른 클래스가 상속 할 수 있다.
- 기본적으로 코틀린의 모든 class는 final 임. (open 어노테이션은 Java의 final과 반대.)
open class AA(x: Int)
4. 오버라이딩
4-1. 메소드 오버라이딩
- 오버라이딩 될 메소드 → open 키워드 필요
- 오버라이딩 된 메소드 → override 키워드 필요
open class AA {
open fun hi() {} // open 키워드가 필요. 오버라이딩 해주려면..
fun bye()
}
class BB() : AA() {
override fun hi() {} // 오버라이딩 하려면 override 키워드 필요.
}
자바같았으면, 그냥 상속받으면 hi()를 가져다가 오버라이딩 가능했지만 코틀린은 키워드를 달아주어야 한다.
4-2. 프로퍼티 오버라이딩
- 메소드 오버라이딩과 유사한 방식으로 한다.
- 오버라이딩 될 프로퍼티 → open 키워드 필요
- 오버라이딩 된 프로퍼티 → override 키워드 필요
open class AA {
open val x: int get {...}
}
class BB: AA() {
override val x : Int = ...
}
4-3. 오버라이딩 규칙
- 같은 멤버에 대한 중복된 구현상속을 받은 경우 상속 받은 클래스는 해당 멤버를 오버라이딩하고 자체 구현을 제공해야 한다.
- super + <클래스> 를 통하여 상위 클래스의 메소드를 호출 할 수 있다.
- 자바처럼 클래스 1개 상속받고, 여러개의 인터페이스를 상속 받을 수 있다.
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") }
fun b() { print("b") }
}
class C() : A(), B {
/*
중복된 구현상속 f() 을 받은 경우
상속받은 클래스는 해당 멤버를 오버라이딩하고,
자체 구현을 제공해야 한다.
*/
override fun f() {
/* 자체 구현이 필요하다. 안하면 컴파일 에러. */
super<A>.f() // call to A.f()
super<B>.f() // call to B.f()
}
}
즉, 모호성을 없애면 된다.
5. 추상클래스
- abstract 멤버는 구현이 없음
- abstract 클래스나 멤버는 open이 필요 없음 (기본적으로 open이 되어있음)
abstract class AA() {
abstract fun f() // 구현부가 없음.
}
class MyClass() : AA {
override fun() { /* 상속 받아 구현*/ }
}