BackEnd/Kotlin

10강. 코틀린에서 상속을 다루는 방법

hanseom 2024. 3. 4. 06:30
반응형
  1. 추상 클래스
  2. 인터페이스
  3. 클래스를 상속할 때 주의할 점
  4. 상속 관련 지시어 정리

 

추상 클래스

  다음은 추상클래스인 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: 상위 타입을 오버라이드 합니다.

감사합니다.

반응형