728x90

상속(Inheritance)이란?

클래스 간의 관계를 구축하는 방법인데, 부모 클래스와 자식 클래스의 관계가 기본이고 자식 클래스는 부모 클래스의 속성과 동작을 포함한다. 부모 클래스 상위 클래스, 기반 클래스라고도 하고 자식 클래스 하위 클래스, 파생 클래스라고도 한다.

 

상속을 하는 이유 

  • 클래스(설계도) 간의 관계를 더욱 끈끈하게 만들 수 있다.
  • 공통적인 요소들이 있다면 부모/자식 클래스를 구분해서 상속관계를 만들 수 있다. 
  • 코틀린은 다른 언어들과 달리 생략된 final 키워드로 기본적으로 상속을 막아둠
  • 무분별한 상속으로 예상치 못한 흐름을 방지하기 위함
  • 코틀린은 open 키워드를 활용해서 상속 관계를 만들 수 있음 
fun main() {
    val animal = Animal("동물울음소리")
    val dog = Dog("멍멍")
    val cat = Cat("야옹")
    val cow = Cow("음메")
    animal.cry() //동물울음소리~~
    dog.cry()   //멍멍~~
    cat.cry()   //야옹~~
    cow.cry()   //음메~~
}
open class Animal(private val crying:String){
     fun cry() {
        println("$crying~~")
    }
}
class Dog(crying:String) : Animal(crying){}
class Cat(crying:String):Animal(crying){}
class Cow(crying: String):Animal(crying){}

 

부모클래스 Animal 앞에 open 키워드로 상속을 가능하게 만듬 

상속을 하면, 자식클래스(Dog, Cat, Cow class)의 인스턴스도 부모클래스(Animal class) 에 있는 cry() 를 사용할 수 있음(private 접근제한자가 붙으면 사용불가)

 

상속의 이점

  • 다형성을 구현할 수 있음
  • 클래스의 내용을 변경해야하는경우 부모 클래스만 변경하는것으로 공수를 줄일 수 있음

Overriding(오버라이딩)

  • 상속받은 부모 클래스의 정보(프로퍼티)나 행위(메소드)를 재설계할 수 있다. 
  • 주로 부모 클래스의 행위(메소드)를 재설계한다.
  • 이러한 행위를 오버라이딩 (Overriding)이라고 한다. 
fun main() {
    val animal = Animal("동물울음소리")
    val dog = Dog("멍멍",10)
    val cat = Cat("야옹")
    val cow = Cow("음메")
    animal.cry() //동물울음소리~~
    dog.cry()   //멍멍!!!! 짖는 강아지의 나이는 10 살
    cat.cry()   //야옹~~
    cow.cry()   //음메~~
}
open class Animal(private val crying:String){
        open fun cry() {
        println("$crying~~")
    }
}
class Dog(private val crying:String,age:Int) : Animal(crying){
    var age = 0
    init {
        this.age = age
    }
    override fun cry() {
        println("$crying!!!! 짖는 강아지의 나이는 $age 살")
    }
}
class Cat(crying:String):Animal(crying){}
class Cow(crying: String):Animal(crying){}

 

그냥 상속했을 때와 비교하면, fun앞에 open 키워드를 붙여주고 Dog class에서 변수를 추가 해주고, cry() 를 overriding 해주면, "멍멍~~"이 아닌, "멍멍!!!! 짖는 강아지의 나이는 10 살" 이 출력된다. 

 

Overloading(오버로딩)

  • 매개변수의 갯수를 다르게하면 동일한 이름으로 메소드를 만들 수 있다.
  • 매개변수의 자료형을 다르게하면 동일한 이름으로 메소드를 만들 수 있다.
  • 반환자료형(반환형)은 오버로딩에 영향을 주지 않음
fun main() {
    val dog = Dog()
    dog.info(true,3) //성별: 수컷, 나이: 3
    dog.info(1,"왈왈") //나이는: 1살 울음소리는 왈왈
}

class Dog {
    fun info(gender: Boolean, age: Int) {
        if (gender) println("성별: 수컷, 나이: $age") else println("성별: 암컷, 나이: $age")
    }
    fun info(age: Int, cry: String) {
        println("나이는: ${age}살 울음소리는 $cry")
    }
}

 

오버로딩은 메소드의 이름은 같은데 매개변수의 수나 자료형을 다르게해서 다른 결과값을 얻기위해 사용됨 

Dog class에 info 메소드는 두 개 이지만, 하나는 boolean 과 int 를 받고, 하나는 int 와 string타입을 받음, 

매개변수에 따라 출력되는 값이 차이가 난다.  

 

Interface(인터페이스)

공통적으로 필요한 기능을 외부에서 추가해줄 수 있다. 

fun main() {
    var dog = Dog("강아지")
    var cat = Cat("고양이")
    var cow = Cow("소")
    var bird = Bird("새")
    dog.run() // 강아지는 뛰는 동물
    cat.run() // 고양이는 뛰는 동물
    cow.run() // 소는 뛰는 동물
    bird.fly() // 새는 나는 동물~
}

open class Animal(private val type: String) {
    fun run() {
        println("${type}는 뛰는 동물")
    }
}

class Dog(type: String) : Animal(type) {}
class Cat(type: String) : Animal(type) {}
class Cow(type: String) : Animal(type) {}
class Bird(private val type:String):Animal(type),FlyAnimal{
    override fun fly() {
        println("${type}는 나는 동물~")
    }
}
interface FlyAnimal{
    fun fly()
}

 

새는 동물이라는 것은 개, 고양이, 소 랑 같지만 새는 뛰지않고 날아다님 

그래서 별도의 기능을 추가하기 위해 interface를 사용한다. (interface안에는 추상메소드로 구현부는 만들어 놓지 않음)

 

 

 

 

+ Recent posts