클래스 앞쪽에 open 키워드를 작성해줘야 상속이 가능하다.
코틀린의 최상위 클래스는 Any 클래스이다. 즉 코틀린의 모든 클래스는 묵시적으로 Any 클래스를 상속받는다.
자식 클래스는 open 키워드가 없기 때문에 더이상 다른 클래스가 상속할 수 없는 최종 클래스이다.
package chap01.section3
//open 클래스이므로 상속 가능 , 주 생성자에 프로퍼티 정의
open class Bird(var name:String, var wing : Int, var beak : String){
fun fly(){
println("fly")
}
fun birdInfo(){
println("새 정보")
println("이름 : $name, 날개 수 : $wing, 부리 : $beak")
}
}
class Lark(irum:String, nalgae:Int, buri:String, var age:Int) : Bird(irum,nalgae,buri){
fun singHighTone(){
println("sing high tone")
}
}
fun main() {
var bird1 = Lark("라크새",2,"새부리",4)
bird1.birdInfo()
}
새 정보
이름 : 라크새, 날개 수 : 2, 부리 : 새부리
Lark 클래스가 Bird 클래스를 상속한다.
Lark 클래스의 프로퍼티를 생성자 형태로 정의한다.
: 뒤에 부모 클래스인 Bird의 생성자에 필요한 인자들을 전달해준다.
Bird 생성자는 name, wing, beak 인자를 받는다.
Lark 생성자가 irum, nalgae, buri, age 를 인자로 받아서 Bird에 irum, nalge, buri를 전달한다.
age는 Lark 클래스에서 새로운 프로퍼티를 정의한 것이다.
주 생성자에서 프로퍼티를 정의하기 때문에 매개변수에서 바로 val, var등과 함께 선언 가능하다.
class AengMu : Bird{ //부 생성자 이용
var language : String
constructor(name : String, wing : Int, beak:String, lang : String) : super(name,wing,beak){
language = lang
}
}
부 생성자를 이용하는 경우 위와 같이 상속 가능하다.
주 생성자는 생성자의 매개변수 부분에서 프로퍼티를 같이 정의한다.
하지만 부 생성자는 language 프로퍼티를 새로 정의하기 위해 따로 변수 선언을 했다.
constructor에서 매개변수를 정의하고 : super()를 통해 부모 클래스의 생성자에 전달할 인자들을 전달했다.
생성자에 정의한 매개변수 이름과 클래스의 프로퍼티 이름이 같다면 클래스 프로퍼티를 this.프로퍼티로 접근해서 매개변수와 구분해 줘야 한다.
같은 이름을 사용하지만 구현 내용이 다르거나 매개변수가 달라서 다른 기능을 수행하는 것
오버로딩 : 메소드 이름은 같지만 매개변수가 달라 호출할 때 전달한 인자에 따라 결정
오버라이딩 : 메소드 자체는 같지만 어느 타입의 객체에서 호출하는 지에 따라 결정
이름이 같지만 매개변수형이 다른 메소드
전달하는 인자에 따라 알아서 호출되는 메소드가 선택된다
open 키워드로 선언된 메소드만 오버라이딩 할 수 있다.
또한 오버라이딩 하는 메소드는 앞에 override를 붙여준다.
메소드 뿐만 아니라 프로퍼티도 open으로 선언하면 하위 클래스에서 오버라이딩 가능하다.
package chap01.section3
//open 클래스이므로 상속 가능 , 주 생성자에 프로퍼티 정의
open class Bird(var name:String, var wing : Int, var beak : String){
//open을 붙인 메소드는 오버라이딩 가능
open fun fly(){
println("fly")
}
fun birdInfo(){
println("새 정보")
println("이름 : $name, 날개 수 : $wing, 부리 : $beak")
}
//sing 메소드 오버로딩 , 호출할 때 전달하는 인자에 따라 알맞은 sing이 호출된다
fun sing(volume:Int){
println("$name singing , volume : $volume")
}
fun sing(volume:Int, purpose : String){
println("$name singing , volume : $volume , purpose : $purpose")
}
}
class FastBird(name:String, wing:Int, beak:String) : Bird(name,wing,beak){
override fun fly(){
println("fly fast")
}
}
class SlowBird(name:String, wing:Int, beak:String) : Bird(name,wing,beak){
override fun fly(){
println("fly slow")
}
}
fun main() {
val bird1 = Bird("새",2,"부리")
val bird2 = FastBird("빠른새",2,"부리")
val bird3 = SlowBird("느린새",2,"부리")
bird1.fly()
bird2.fly()
bird3.fly()
bird3.sing(5)
bird3.sing(10,"경고")
}
fly
fly fast
fly slow
느린새 singing , volume : 5
느린새 singing , volume : 10 , purpose : 경고
오버로딩
Bird 클래스에서 sing 메소드를 2개 정의했다. 매개변수가 다르다.
main에서 sing 호출 시 호출하는 인자에 따라 다른 sing이 호출된 것을 확인할 수 있다.
오버라이딩
fly 메소드를 오버라이딩한다. Bird 클래스의 fly 메소드에는 open을 붙여 오버라이딩이 가능하도록 했다.
FastBird와 SlowBird 클래스에서는 fly 앞에 override를 붙였다.
bird1, 2, 3에서 각각 fly를 호출하지만 실행 결과는 다르다.
fun main() {
val bird1 : Bird = Bird("새",2,"부리")
val bird2 : Bird = FastBird("빠른새",2,"부리")
val bird3 : Bird = SlowBird("느린새",2,"부리")
bird1.fly()
bird2.fly()
bird3.fly()
bird3.sing(5)
bird3.sing(10,"경고")
}
main에서 bird1,2,3의 객체 자료형을 Bird로 선언했다. 하지만 생성자는 각각 Bird, FastBird, SlowBird로 호출했다.
이렇게 하면 bird 1,2,3는 Bird 자료형으로 Bird를 관리하는 자료구조로 관리할 수 있다. 하지만 오버라이딩에 의해 같은 메소드를 호출해도 각각 오버라이딩 된 메소드를 호출해 다르게 동작할 수 있다.
파생 클래스(자식 클래스)에서 오버라이딩 하지 못하게 하려면 final 키워드를 붙여준다.
this는 현재 클래스, super는 상위 클래스 참조에 사용
Developer는 Person을 상속한다.
Developer의 첫번째 부 생성자는 firstName을 인자로 받고 this로 Developer의 매개변수가 2개인 생성자를 this로 호출한다. age는 10을 기본값으로 받아서 정의했다.
두번째 부 생성자는 super를 이용해서 Person의 매개변수가 2개인 두번째 부 생성자를 호출한다.
부모 클래스 Base를 자식 클래스 Child가 상속한다.
부모 클래스의 프로퍼티와 메소드에는 open이 붙어 상속 가능하다.
Child 내에는 이너클래스 Inside가 있다.
Inside 클래스의 test 메소드에서 Inside 클래스의 외부 클래스 Child가 상속하는 Base 클래스의 프로퍼티나 메소드에 접근하기 위해서 super@Child 어노테이션을 사용한다. 즉 Child 클래스의 super 클래스에 접근한다는 뜻이다.
클래스 C는 클래스 A를 상속하고 인터페이스 B를 구현한다.
A와 B에는 각각 f() 메소드가 존재한다.
C에서 각각 어느 부모 클래스의 메소드인지 구분해서 호출해야 하기 때문에 앵글브라켓을 활용한다.
super<A>.f()
super<B>.f()
참고 : 같은 패키지에 이름이 같은 클래스가 있으면 오류 발생
잠시 테스트를 위해 사용한다면 코드 최상단의 패키지 부분을 살짝 바꿔주면 된다. 실제 패키지 경로랑 다르더라도 실행은 된다.