추상 클래스 abstract class

추상 클래스란 추상 함수를 포함하는 클래스를 의미 합니다.

추상함수, 추상 프로퍼티

  • 추상 함수는 미완성 함수 혹은 실행 영역이 없는 함수를 의미합니다.

  • 추상 함수는 반드시 함수 선언 부분에 abstract 예약어가 있어야 합니다.

  • 추상 프로퍼티는 초깃값 없이 선언만 있는 프로퍼티를 말합니다.

  • 추상 프로퍼티는 반드시 프로퍼티 선언 부분에 abstract 예약어가 있어야 합니다.

  • 추상 함수, 추상 프로퍼티는 상속과 관련이 있어 클래스 내부에서만 사용할 수 있습니다.

추상 클래스 선언

  • 추상 함수를 포함하는 클래스는 꼭 클래스 선언 부분에 abstract 예약어가 있어야 합니다.

  • 추상 프로퍼티를 포함하는 클래스는 꼭 클래스 선언 부분에 abstract 예약어가 있어야 합니다.

abstract class AbstractTestClass {
    fun myFun1(){
        // ...
    }
    abstract fun myFun2()       // 추상 함수를 포함

    abstract val data1 : String // 추상 프로퍼티 포함
}

추상 클래스 이용

  • 추상 클래스는 객체를 생성할 수 없으며, 추상 클래스를 상속받는 하위 클래스의 객체를 생성해서 이용 해야 합니다.

  • 추상 클래스는 선언에 open 예약어를 명시하지 않아도 다른 클래스가 상속할 수 있습니다.

    • 추상 클래스를 상속받는 클래스는 는 상위 추상 클래스에 정의된 추상 함수와 추상 프로퍼티를 모두 재정의 해야 합니다.

보통 공통된 함수를 사용하지만 구체적인 정의는 따로 작성해야할 경우 abstract를 이용해 무조건 재정의 하게끔 사용 합니다.

ex)

abstract class Human {
    abstract var name: String
    abstract fun sayNameAndHi()
}

class Lee: Human() {
    override var name = "lee"
    override fun sayNameAndHi() {
        println("hi my name is $name")
    }
}

class Kim: Human() {
    override var name = "kim"
    override fun sayNameAndHi() {
        println("hi i'm $name")
    }
}

// ...
Lee().sayNameAndHi()
Kim().sayNameAndHi()

결과

hi my name is lee
hi i'm kim

인터페이스

객체 생성이 불가능 하며 추상 함수를 선언하는 것이 주목적 입니다.

추상 클래스는 객체를 정의할 목적(is a)이며 객체가 포함하는 행위 중 하위에서 재정의해서 사용할 함수만 추상형으로 명시하고
인터페이스는 객체를 정의할 목적이 아니라 어떤 객체가 되든 그런 행동을 가진다는 것(has a)을 명시하기 위해 사용 됩니다.

인터페이스 선언 및 구현

  • 인터페이스는 객체로 생성할 수 없습니다.

  • 인터페이스는 클래스가 아니므로 생성자가 없으며 구현하는 클래스는 콜론 : 을 이용합니다.

  • 인터페이스의 프로퍼티, 추상 함수는 명시하지 않아도 기본으로 abstract가 적용됩니다.

  • 인터페이스에는 구현 내용이 있는 함수를 정의 할수도 있으며 그대로 이용할 수 있습니다.

  • 클래스에서 인터페이스를 구현할 때 여러 인터페이스를 나열해 한꺼번에 구현할 수 있습니다.

형식 ex)

class 클래스명 : 인터페이스1

ex)

interface Human {
    var name: String
    fun sayNameAndHi()
    fun justHi(){
        println("Hi")
    }
}

class Lee : Human {
    override var name = "lee"
    override fun sayNameAndHi() {
        justHi()
        println("hi my name is $name")
    }
}

class Kim : Human {
    override var name = "kim"
    override fun sayNameAndHi() {
        println("hi i'm $name")
    }
}

// ...
val lee = Lee()
val kim = Kim()

lee.sayNameAndHi()
kim.justHi()
kim.sayNameAndHi()

결과

Hi
hi my name is lee
Hi
hi i'm kim

클래스에서 여러 인터페이스 구현

  • 클래스에서 이러 인터페이스를 한꺼번에 구현할 수 있습니다

ex)

interface MyInterface1 { 
    fun myFun1()
}
interface MyInterFace2 {
    fun myFun2()
}
class MyClass : MyInterface1, MyInterFace2 {
    override fun myFun1() { }
    override fun myFun2() { }
}

클래스에서 상속과 인터페이스 혼용

  • 상속받을 클래스는 하나만 명시할 수 있으며, 인터페이스는 여러개 구현할 수 있습니다

ex)

open class Super { }
interface MyInterface1 { 
    fun myFun1()
}
interface MyInterFace2 {
    fun myFun2()
}

class Sub : Super(),MyInterface1,MyInterFace2 {
    override fun myFun1() { }
    override fun myFun2() { }
}

오버라이드 함수 식별

  • 상위 클래스에 정의된 함수명과 인터페이스에 정의된 함수명이 중복되는 경우 함수를 식별해서 이용해야 합니다.

같은 이름의 추상 함수가 여러 개일 때

  • 재정의 해야하는 추상 함수는 여러 개인데 이름이 모두 같은 경우 한번만 함수를 재정의해주면 됩니다.

ex)

interface MyInterFace1 {
    fun funA()
}
interface MyInterFace2 {
    fun funA()
}

abstract class Super {
    abstract fun funA()
}

class Sub : Super(),MyInterFace1,MyInterFace2{
    override fun funA() {
        // ...
    }
}

같은 이름으로 구현된 함수가 여러 개일 때

  • 같은 이름으로 구현된 함수가 여러 개인 경우 해당 함수를 꼭 override 해야 합니다.

  • 인터페이스명을 명시해 사용할 수 있습니다.

    • super<인터페이스명>.함수명

ex)

interface MyInterface1 { 
    fun funA(){
        // ...
    }
}
interface MyInterface2 { 
    fun funA(){
        // ...
    }
}
class MyClass : MyInterface1,MyInterface2 {
    override fun funA(){
        super<MyInterface1>.funA()
        super<MyInterface2>.funA()
    }
}

참조 : 깡샘의 코틀린 프로그래밍