고도고도
🍎🍏
고도고도
전체 방문자
7,127
오늘
0
어제
11
  • 분류 전체보기 (144)
    • 🔨 프로젝트 (0)
      • TP 1 (0)
      • WhiteHCCTV (0)
      • FootPrint (0)
    • 💻 개발 (38)
      • TIL (16)
      • Android (6)
      • Kotlin (4)
      • Flutter (5)
      • Node.js (5)
      • Error (2)
    • ✏️ 알고리즘 (6)
      • Graph (6)
      • String (0)
      • Sort (0)
    • ✍️ 코테 준비 (44)
      • Math (1)
      • Implementation (3)
      • String (3)
      • Brute Force (5)
      • Back Tracking (7)
      • Greedy (0)
      • Dynamic Programming (13)
      • Binary Search (1)
      • DFS, BFS (5)
      • Shortest Path (2)
      • Two Pointer (4)
      • MST (0)
    • 📚 CS (6)
      • Operating System (6)
    • ⛹️ 라이프 (50)
      • 2020 겨울방학 모칵코(팀) (13)
      • 2020 겨울방학 모각코(개인) (13)
      • 2021 여름방학 모칵코(팀) (8)
      • 2021 여름방학 모각코(개인) (7)
      • 코딩 테스트 (1)
      • 회고 (7)

블로그 메뉴

  • 홈
  • 깃허브

인기 글

  • [TIL] 22.03.13
    2022.03.13
    [TIL] 22.03.13
  • [문자열 / Kotlin] 2020 KAKAO⋯
    2022.03.11
    [문자열 / Kotlin] 2020 KAKAO⋯
  • [TIL] 22.03.20
    2022.03.20
    [TIL] 22.03.20
  • [퍼듀 일기] 어느덧 한 달째
    2022.03.01
    [퍼듀 일기] 어느덧 한 달째
  • [구현 / Kotlin] 2022 SK ICT F⋯
    2022.03.12
    [구현 / Kotlin] 2022 SK ICT F⋯

최근 글

  • [프로그래머스] 124 나라의 숫자
    2022.06.09
    [프로그래머스] 124 나라의 숫자
  • [LeetCode] 167. Two Sum II -⋯
    2022.06.09
    [LeetCode] 167. Two Sum II -⋯
  • [Android] 알림 클릭시 Activit⋯
    2022.06.08
    [Android] 알림 클릭시 Activit⋯
  • [Android] 백그라운드에서 소켓⋯
    2022.06.08
    [Android] 백그라운드에서 소켓⋯
  • [TIL] 22.06.03 - iOS 화면 전환
    2022.06.03
    [TIL] 22.06.03 - iOS 화면 전환

최근 댓글

  • 잘보고 갑니다~
    개갓세
  • 좋은 글이네요
    날인로세
  • 잘 보고 갑니다^^
    프로퍼티
hELLO · Designed By 정상우.
고도고도

🍎🍏

[코틀린 완전정복] 추상 클래스와 인터페이스
💻 개발/Kotlin

[코틀린 완전정복] 추상 클래스와 인터페이스

2022. 4. 22. 19:09

추상 클래스

추상 클래스 VS 인터페이스

추상 클래스 는 대략적인 설계의 명세와 공통의 기능을 구현한 클래스이다. 즉, 구체적이지 않은 것이다. 추상 클래스 를 상속하는 하위 클래스 는 추상 클래스의 내용을 더 구체화 해야 한다.

오잉? 그럼 추상 클래스랑 인터페이스는 같은 거 아냐? 🤔

엄밀히 말하면 다르다. 인터페이스 역시 대략적인 설계 명세를 구현하고 인터페이스 를 상속하는 하위 클래스 에서 이를 구체화하는 것은 동일하다. 하지만 인터페이스에서는 프로퍼티의 상태 정보를 저장할 수 없다.

 

다시 말하면 인터페이스 에서는 프로퍼티의 초기화 가 불가능하다는 것이다.

interface Vehicle {
    val name : String
    val color : String
    val weight : Double
}

interface Pet {
    val name : String = "puppy" // 불가능!
}

Pet Interface 의 경우 정의와 동시에 초기화까지 해주고 있는데 인터페이스 에선 불가능하다.

추상 클래스 사용해보기

추상 클래스 는 위에서 말한 것처럼 구체화되지 않은 클래스이기 때문에 일반적인 객체를 생성하는 방법으로 인스턴스화될 수 없다. 일단 한번 정의해보자. 우선 추상 클래스 를 정의하기 위해선 abstract 라는 키워드를 사용해야 한다. 또한 클래스 내에서의 프로퍼티나 메소드도 abstract로 선언할 수 있다. 이를 상속받는 클래스에서 구체화하겠다는 의미가 된다. 하지만 이를 사용하기 위해선 해당 클래스가 추상 클래스가 되어야한다.

// abstract로 정의한 추상 클래스이다. 주생성자를 사용했다.
abstract class Vehicle(val name : String, val color : String, val weight : Double) {
    // abstract로 정의한 추상 프로퍼티이므로 하위 클래스에서 반드시 재정의해야한다.
    abstract var maxSpeed : Double 

    // 초기값을 갖는 일반 프로퍼티 (인터페이스에서는 불가능)    
    var year = "2021"

    // abstract로 정의한 추상 메소드이므로 하위 클래스에서 반드시 재정의해야한다.
    abstract fun start()
    abstract fun stop()

    fun displaySpecs() {
        println("Name : $name, Color : $color, Weight : $weight, Year : $year, MaxSpeed : $maxSpeed")
    }
}

Vehicle 클래스 는 abstract로 정의한 추상 클래스이므로 기본적인 설계만 정의하고 있다. abstract 를 사용한 maxSpeed, start(), stop()은 반드시 하위 클래스에서 재정의 해줘야한다.

여기서 잠깐! 클래스를 상속하기 위해선 부모 클래스를 open 키워드로 정의해야 하는데 추상 클래스에서도 해줘야 하나요? 🤔

이미 코드를 통해 느꼈겠지만, 추상 클래스 에서는 open 키워드 를 사용하지 않아도 된다. 추상 프로퍼티 나 추상 메소드 도 마찬가지다!

 

위에서 정의한 Vehicle 클래스를 상속해보자.

class Car(name : String, color : String, weight : Double, override var maxSpeed : Double) : Vehicle(name, color, weight) {
    override fun start() {
        // 재정의
        println("Car start")
    }

    override fun stop() {
        // 재정의
        println("Car Stop")
    }
}

class Bicycle(name : String, color : String, weight : Double, override var maxSpeed : Double) : Vehicle(name, color, weight) {
    override fun start() {
        // 재정의
        println("Bicycle start")
    }

    override fun stop() {
        // 재정의
        println("Bicycle Stop")
    }
}

fun main() {
    val car = Car("Matiz", "Yellow", 1000, 150)
    val bicycle = Bicycle("Bike", "Red", 150, 100)

    // 새로운 값 할당
    car.year = "2020"

    car.displaySpec()
    car.start()
    bicycle.displaySpec()
    bicycle.start()

displaySpec 은 추상 클래스 가 갖고 있던 일반 메소드 이다. start 와 stop 은 추상클래스 를 상속받은 자식 클래스 에서 오버라이딩한 메소드 이다. 추상 클래스에서 abstract로 정의한 프로퍼티나 메소드들은 자식 클래스에서 반드시 재정의되어야한다.

그렇다면 혹시, 추상 클래스를 상속받는 하위 클래스를 정의하지 않고도 추상 클래스를 사용할 수 있을까? 🤔

사용할 수 있다! object 키워드를 사용하면 된다. (object 이 친구 만능이네...?)

abstract class Printer {
    abstract fun print()
}

val myPrinter = object : Printer() {
    override fun print() {
        println("print 메소드가 재정의되었습니다")
    }
}

fun main() {
    myPrinter.print()
}

인터페이스

코틀린 에서는 다른 언어와 다르게 메소드 에 구현 내용을 포함할 수 있다.

interface Pet {
    var category : String // 추상 프로퍼티
    fun feeding()  // 추상 메소드
    fun patting() { // 구현부를 포함할 수 있다. 구현부를 포함하면 일반 메소드
        println("Keep patting")
    }
}

추상클래스 와 다르게 abstract 키워드를 사용하지 않는다. 또한 앞서 말한 것처럼 상태를 저장할 수가 없으므로 프로퍼티에 기본 값을 가질 수가 없다.

인터페이스 사용하기

class Cat(override var category : String) : Pet { // 주생성자를 이용
    override fun feeding() {
        println("Feeding 메소드가 구현되었습니다.")
    }
}

fun main() {
    val obj = Cat("Small")
    obj.feeding() // 구현된 메소드
        obj.patting()// 일반 메소드
}

인터페이스에서 값 저장하기

아니 선생님, 인터페이스에서는 프로퍼티에 값을 저장할 수 없다고 하셨잖아요 😥

하지만 예외가 있다. val 로 선언한 프로퍼티 는 게터 를 통해서 필요한 내용을 구현할 수 있다.

interface Pet {
    var category : String // 추상 프로퍼티
    val message : String // val로 선언하면 게터의 구현이 가능하다.
        get() = "I'm cutty"

    fun feeding()  // 추상 메소드
    fun patting() { // 구현부를 포함할 수 있다. 구현부를 포함하면 일반 메소드
        println("Keep patting")
    }
}

게터 가 사용 가능하지만 그렇다고 보조필드 가 사용가능한 것은 아니다.

인터페이스의 이점

인퍼페이스를 사용하면 뭐가 좋을까? 일단 코드의 재사용성이 올라간다. 한마디로 간결해진다는 점이다. 또 인터페이스를 이용해서 클래스 간의 의존성을 제거할 수 있다. 뿐만 아니라 다중 상속도 가능하다. 코틀린에서는 자바와 다르게 클래스에서 부모 클래스를 상속할 때는 1개의 클래스만 가능하다. 하지만 인터페이스를 활용하면 다중 상속이 가능해진다!

 

아래는 두 개의 인터페이스를 통해 다중 상속을 구현한 코드이다.

interface Bird {
    val wings : Int
    fun fly()
    fun jump() { // 구현된 일반 메소드
        println("Bird jump")
    }
}

interface Horse {
    val maxSpeed : Int
    fun run()
    fun jump() { // 구현된 일반 메소드
        println("jump!, max speed : $maxSpeed")
    }
}

class Pegasus : Bird, Horse {
    override val wings : Int = 2
    override val maxSpeed : Int = 100
    override fun fly() {
        println("The Pegasus Fly!")
    }
    override fun run() {
        println("The Pegasus Run!")
    }
    override fun jump() {
        super<Horse>.jump() {
            println("The Pegasus jump")
        }
    }
}

구현부가 있는 메소드의 경우 필요에 따라 오버라이딩을 진행하면 된다. 만약 인터페이스에서 구현한 메소드의 이름이 같은 경우 super<인터페이스 이름>.메소드명 을 통해 구분할 수 있다.

저작자표시비영리변경금지

'💻 개발 > Kotlin' 카테고리의 다른 글

[코틀린 완전정복] 공변성, 반공변성, 무변성  (0) 2022.05.02
[코틀린 완전정복] 제네릭  (0) 2022.04.25
[코틀린 완전정복] 여러 종류의 클래스  (0) 2022.04.23
[코틀린 완전정복] 추상 클래스와 인터페이스  (0) 2022.04.22
    '💻 개발/Kotlin' 카테고리의 다른 글
    • [코틀린 완전정복] 공변성, 반공변성, 무변성
    • [코틀린 완전정복] 제네릭
    • [코틀린 완전정복] 여러 종류의 클래스
    고도고도
    고도고도
    좋아하는 것을 하자\n 스위프트 찍먹중
    댓글쓰기
    다음 글
    [코틀린 완전정복] 여러 종류의 클래스
    • 이전
    • 1
    • 2
    • 3
    • 4
    • 다음