-
10강. 코틀린에서 상속을 다루는 방법BackEnd/Kotlin 2024. 3. 4. 06:30반응형
- 추상 클래스
- 인터페이스
- 클래스를 상속할 때 주의할 점
- 상속 관련 지시어 정리
추상 클래스
다음은 추상클래스인 JavaAnimal 코드입니다.
public abstract class JavaAnimal { protected final String species; protected final int legCount; public JavaAnimal(String species, int legCount) { this.species = species; this.legCount = legCount; } abstract public void move(); public String getSpecies() { return species; } public int getLegCount() { return legCount; } }
Kotlin으로 구현하면 다음과 같습니다.
abstract class Animal( protected val species: String, protected val legCount: Int, ) { abstract fun move() }
다음은 JavaAnimal을 상속한 JavaCat 코드입니다.
public class JavaCat extends JavaAnimal { public JavaCat(String species) { super(species, 4); } @Override public void move() { System.out.println("고양이가 사뿐 사뿐 걸어가~"); } }
Kotlin으로 구현하면 다음과 같습니다.
class Cat( species: String ) : Animal(species, 4) { // 상위 클래스의 생성자 바로 호출 override fun move() { println("고양이가 사뿐 사뿐 걸어가~") } }
- extends 키워드를 사용하지 않고 : 을 사용합니다. (Convention: 타입을 쓸 때는 변수명에서 한 칸 뛰지 않고 :을 붙이고, 상속에서는 한 칸 뛰고 :을 붙입니다.)
- 상속 시 상위 클래스의 생성자를 바로 호출합니다.
- override 지시어를 필수적으로 붙여 주어야 합니다.
다음은 JavaPenguin 클래스입니다.
public final class JavaPenguin extends JavaAnimal { private final int wingCount; public JavaPenguin(String species) { super(species, 2); this.wingCount = 2; } @Override public void move() { System.out.println("펭귄이 움직입니다~ 꿱꿱"); } @Override public int getLegCount() { return super.legCount + this.wingCount; } }
Kotlin으로 구현하면 다음과 같습니다.
abstract class Animal( protected val species: String, protected open val legCount: Int, // override property ) { abstract fun move() }
class Penguin( species: String ) : Animal(species, 2) { private val wingCount: Int = 2 override fun move() { println("펭귄이 움직입니다~ 꿱꿱") } override val legCount: Int get() = super.legCount + this.wingCount }
- 프로퍼티에 대한 override를 할 때(legCount), 추상 프로퍼티가 아니라면 open 키워드를 붙여줘야 합니다.
- 상위 클래스에 접근하는 키워드는 super입니다.
Java, Kotlin 모두 추상 클래스는 인스턴스화 할 수 없습니다.
인터페이스
다음은 JavaFlyable과 JavaSwimmable을 구현한 JavaPenguin 클래스입니다.
public interface JavaFlyable { default void act() { System.out.println("파닥 파닥"); } } public interface JavaSwimable { default void act() { System.out.println("어푸 어푸"); } } public final class JavaPenguin extends JavaAnimal implements JavaSwimable, JavaFlyable { private final int wingCount; ... 생략 ... @Override public void act() { JavaSwimable.super.act(); JavaFlyable.super.act(); } }
Kotlin으로 구현하면 다음과 같습니다.
interface Swimable { fun act() { println("어푸 어푸") } } interface Flyable { fun act() { println("파닥 파닥") } } package com.lannstark.lec10 class Penguin( species: String ) : Animal(species, 2), Swimable, Flyable { private val wingCount: Int = 2 ... 생략 ... override fun act() { super<Swimable>.act() super<Flyable>.act() } }
- Kotlin의 인터페이스는 default 키워드 없이 메서드 구현이 가능합니다.
- Kotlin의 인터페이스도 추상 메서드를 만들 수 있습니다.
- Kotlin에서 인터페이스 구현도 :을 사용합니다.
- 중복되는 인터페이스를 특정할 때는 super<타입>.함수를 사용합니다.
Java, Kotlin 모두 인터페이스를 인스턴스화 할 수 없습니다.
Kotlin에서는 backing field가 없는 프로퍼티를 인터페이스에 만들 수 있습니다.
interface Swimable { val swimAbility: Int get() = 1 fun act() { println(swimAbility) println("어푸 어푸") } }
클래스를 상속받을 때 주의할 점
다음 코드의 수행 결과를 보면 출력되는 number의 값이 100도 아니고 300도 아닌 0입니다. 그 이유는, Base 클래스(상위 클래스)의 생성자가 실행되는 시점에 Derived 클래스(하위 클래스)의 number 값에 대한 초기화가 이루어지지 않은 상태이기 때문입니다.
그러므로, 상위 클래스를 설계할 때 생성자 또는 초기화 블록에 사용되는 프로퍼티에는 open을 피해야 합니다.
fun main() { Derived(300) } open class Base( open val number: Int = 100 ) { init { println("Base Class") println(number) } } class Derived( override val number: Int ) : Base(number) { init { println("Derived Class") } } [수행 결과] Base Class 0 Derived Class
상속 관련 지시어
- final: default로, override를 할 수 없게 합니다.
- open: override를 열어 줍니다.
- abstract: 반드시 override 해야 합니다.
- override: 상위 타입을 오버라이드 합니다.
감사합니다.
반응형'BackEnd > Kotlin' 카테고리의 다른 글
12강. 코틀린에서 object 키워드를 다루는 방법 (0) 2024.03.07 11강. 코틀린에서 접근 제어를 다루는 방법 (0) 2024.03.07 9강. 코틀린에서 클래스를 다루는 방법 (0) 2024.03.03 8강. 코틀린에서 함수를 다루는 방법 (0) 2024.02.21 7강. 코틀린에서 예외를 다루는 방법 (0) 2024.02.07