Kotlin은 Java와 무엇이 다른가? (9) - 상속
상속
Kotlin에서 상속은 문법이 같은 부분보다는 다른 부분이 좀 더 많다.
추상 클래스(Abstract Class)
- 추상 클래스는 구현이 일부 없는 불안전한 클래스이다.
- 추상 클래스로 공통된 특성 뼈대를 만들고 상속 받는 클래스에서 살을 붙이는 형식으로 많이 쓰인다.
추상 클래스 선언 방법
Kotlin에서 추상 클래스는 abstract 키워드로 선언한다.
abstract class Vehicle(val brand: String, open var model: String) {
abstract fun start()
abstract fun stop()
}
- 추상 메서드도 앞에 abstract를 붙여 사용 가능하다.
- Java와 같은점은 추상클래스는 인스턴스화할 수 없다.
상속
Kotlin에서 상속 할 때에는 : 객체
를 가지고 상속한다.
class ElectricCar(val brand: String) : Vehicle(brand, ""){
override fun start() {
println("$brand $model 전기차 출발")
}
override fun stop() {
println("$brand $model 전기차 멈춤")
}
override var model: String = "전기차"
}
중요한 점은
- Type을 쓸 때도
:
을 이용해서 사용한다.- 둘의 차이점은
- Type을 쓸 때에는
Type:
띄어쓰기 없이 사용 - 상속에 사용할 때에는
: 객체
한칸 띄어서 사용
- 오버라이드를 하는 경우에는 override키워드를 사용해서 구현
- 프로퍼티를 상속하는 경우에는 상위 프로퍼티에 open 키워드를 붙여주는 것이다.
인터페이스
Kotlin의 인터페이스는 Java와 유사한 점이 많다.
interface Vehicle {
fun start() {
println("출발")
}
fun stop() {
println("멈춤")
}
// 추상 메서드
fun drive()
}
- Kotlin 인터페이스의 메서드는 기본적으로 추상 메서드이며, 로직이 있는 경우에만 default method가 된다.
- 추상 method를 사용하고 싶다면 아무것도 있지 않은 method를 구현하면 된다.
인터페이스 구현 방법
Kotlin에서 인터페이스도 상속과 마찬가지로 :
키워드를 가지고 구현할 수 있다.
class ElectricCar : Vehicle{
override fun start() {
println("전기차 시작")
}
override fun stop() {
super<Vehicle>.stop()
}
}
- 상속과 똑같이 override 키워드를 사용해서 메서드를 구현한다.
- 다른 점은 상위 인터페이스의 함수를 overide 할 때에는
super <객체>. 메서드로
구현이 가능하다. - Java와 마찬가지로 인터페이스를 인스턴스화할 수 없다.
Kotlin에서 조금 더 추가되는 점은 상위 인터페이스에 backing field가 없는 프로퍼티를 인터페이스에 만들 수 있다.
interface Vehicle {
fun start() {
println("출발")
}
fun stop() {
println("멈춤")
}
// 추상 메서드
fun drive()
val brand: String
get() = "Hyundai"
}
class ElectricCar : Vehicle{
override fun start() {
println("전기차 시작")
}
override fun stop() {
super<Vehicle>.stop()
}
override val brand: String
get() = "KIA"
}
위와 같이
상위 인터페이스에 프로퍼티가 backing field가 사용되지 않았다면 구현체에서 override 해서 사용이 가능하다.
상속 시 주의점
open class Vehicle(open val brand: String = "Hyundai") {
init {
println("Vehicle 초기화: brand = $brand")
}
}
class Car(override brand: String, val model: String) : Vehicle(brand) {
private val description: String
init {
println("Car 초기화 시작")
println("model = $model")
description = "$brand $model"
println("description = $description")
}
}
fun main() {
val myCar = Car("Toyota", "Corolla")
}
해당 코드의 결과는 어떻게 될까?
Vehicle 초기화: brand =
Car 초기화 시작
model = Corolla
description = Toyota Corolla
Vehicle 초기화 할 때 brand가 나오지 않게 될 것이다.
brand가 나오지 않는 이유는 상속을 할 때 생성자 호출 순서에 있다.
- Car가 초기화되기 전에 Vehicle이 먼저 초기화가 된다.
- Vehicle이 초기화될 때 하위 Car에 brand를 가져오게 되는데
- 하지만 Car는 아직 초기화가 되지 않았으므로 brand에는 아무것도 없다.(Default Parameter를 선언했음에도)
이러한 문제를 막기 위해서상위 클래스를 설계할 때 생성자 또는 초기화 블록에 사용되는 프로퍼티에는 open을 피해야 한다.라는
주의점이 있다.
요약
- Kotlin에서 추상 클래스는 abstract 키워드를 사용해 구현한다.
- 상속을 할 때에는
: 객체
키워드를 사용한다. - Kotlin에서 모든 클래스와 메서드는 기본적으로 final이며, 상속이나 오버라이드를 허용하려면 open 키워드를 사용해야 한다.
- Kotlin 인터페이스의 메서드는 기본적으로 추상 메서드이며, 로직이 있는 경우에만 default method가 된다.
- 인터페이스 구현체도
: 객체
키워드를 사용한다. - 상위 인터페이스에 프로퍼티가 backing field가 사용되지 않았다면 구현체에서 override 해서 사용이 가능하다.
- 상위 클래스를 설계할 때 생성자 또는 초기화 블록에 사용되는 프로퍼티에는 open을 피해야 한다.
출처 : 자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)
자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide) 강의 | 최태현 - 인프런
최태현 | 이 강의를 통해 Kotlin 언어의 특성과 배경, 문법과 동작 원리, 사용 용례, Java와 Kotlin을 함께 사용할 때에 주의할 점 등을 배울 수 있습니다., 요즘 대세인 코틀린을 공부하고 싶다면?⭐ J
www.inflearn.com