코틀린(Kotlin)

코틀린(kotlin) : 클래스와 상속 class and inheritance

알통몬_ 2018. 1. 29. 12:32
반응형


공감 및 댓글은 포스팅 하는데

 아주아주 큰 힘이 됩니다!!

포스팅 내용이 찾아주신 분들께 

도움이 되길 바라며

더 깔끔하고 좋은 포스팅을 

만들어 나가겠습니다^^

 


이번 포스팅에서는 코틀린의 클래스와 상속에 대해 공부합니다.

클래스는 class 키워드를 사용해서 선언합니다.

class Example2 {
}

클래스 내부에 아무 내용도 없을 경우 {}도 생략가능합니다.

class Example2


클래스는 하나 또는 그 이상의 생성자를 가지는데요.

사용자가 아무 생성자도 선언하지 않으면, 기본 생성자가 자동적으로 생성됩니다.

생성자를 선언하는 방법은 여러가지가 있는데요.


기본 생성자의 경우는 클래스이름 옆에 constructor 키워드를 이용해서 생성하는데요,

생성자 앞에 private, protected, internal, public 등의 키워드나 어노테이션이 없을 경우에는

constructor키워드를 생략할 수도 있습니다.

class Example2 constructor(age : Int) {
}

class Example2 (age : Int) {
}


그리고 기본 생성자는 자바와 다르게 코드 블록을 가질 수 없는데요.

 init {} 블록을 통해 초기화할 수 있습니다.

그리고 init{} 블록은 꼭 한 개일 필요는 없습니다.


class Example2 (age : Int) {

private var age : Int = 0

init {
this.age = age
print(age)
}
}


보조 생성자

보조 생성자는 자바에서 생성자를 생성하듯이 생성합니다.


class Example {

constructor(name: String) {
print(name)
}
}

그리고 보조 생성자를 사용하려는데, 이미 기본 생성자가 존재한다면 

직접적이든 간접적이든 this 키워드를 이용해서 기본 생성자에 위임해 주어야 합니다.


class Example(){
constructor(name: String, age : Int) : this(){
print("$name $age")
}
init {
print(20)
}

}


클래스의 인스턴스 : 객체의 생성


val ex = Example("altong", 27)


객체 생성 시에는 자바에서는 new 키워드를 사용하지만, 코틀린에서는 그냥

클래스 이름(매개변수...) 로 생성합니다. 사용 법은 동일합니다.


클래스의 멤버들

클래스에는 생성자와 init{} 초기화 블록, 함수, 프로퍼티, 중첩 클래스나, 내부 클래스,

객체 선언을 포함할 수 있습니다.


상속 :

코틀린에서는 명시적으로 부모클래스를 가지지 않으면, 

기본적으로 Any 클래스를 상속받습니다.

class Example : {} 이렇게 클래스를 선언하면 보이지는 않지만, 자동적으로

Any 클래스를 상속 받는 것입니다.

Any 클래스는 자바의 java.util.Object 클래스와는 부분적으로 다른데요,

Any 클래스에는 equal(), hashCode(), toString() 말고는 다른 멤버를 가지지 않습니다.


코틀린에서 기본적으로 클래스들은 모두 final 클래스입니다.

때문에 부모 클래스가 되려면 open 키워드를 사용해야 합니다.

Parent 밑에 빨간 줄이 뜨죠?? 에러메시지를 보면 final 클래스는 상속의 대상이 될 수 없다.

입니다. Parent 클래스 앞에 open 키워드를 붙여줘야 정상적으로 상속을 할 수 있습니다.

그리고 상속은 자바에서는 extends 예약어를 쓰지만, 코틀린에서는 :(콜론)을 사용합니다.

그리고 부모 클래스에 기본 생성자가 있다면, 자식 클래스에서 위임을 해주어야 합니다.

open 키워드를 명시해주니 에러가 사라졌죠?


그런데 만약 부모 클래스에 기본생성자는 없고, 안드로이드의 View, Button 등의

컴포넌트 클래스들처럼 보조 생성자가 여러 개일 경우에는 어떻게 해야할까요?


class MyView : View {
constructor(ctx: Context) : super(ctx)

constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

이렇게 생성자들을 모두 선언해주어야 합니다.


인터페이스 상속 :

인터페이스는 생성자를 가질 수 없습니다.

그리고 인터페이스에 선언된 멤버들은 기본 값이 final이 아닌 open입니다.

인터페이스 또한 상속 받을 수 있습니다. implements 키워드가 아니라,

클래스 상속과 똑같이 : 를 사용하고, 앞에 클래스 상속을 이미 받고 있다면,

,(콤마)를 찍고 상속 받을 인터페이스를 선언하면 됩니다.


open class Parent(a: Int) {
fun funB() {
println("ParentA funB()")
}
open fun funA() {
println("Parent funA()")
}
}

interface IParent {
fun funA() {
print("IParent funIA()")
}
}

class Example(age: Int) : Parent(age), IParent {
constructor(name: String, age: Int) : this(age) {
println("$name $age")
}

override fun funA() {
println("Child FunA()")
super<IParent>.funA()
super<Parent>.funA()

}


}

만약 클래스와 인터페이스를 모두 상속받았을 때 상속받은 클래스와 인터페이스에

같은 이름의 메서드가 존재할 경우 super 키워드를 이용해서 부모의

멤버를 호출하고 싶다면 super<클래스이름 or 인터페이스이름>.멤버 처럼 호출하면 됩니다.

super<IParent>.funA()
super<Parent>.funA()


메서드 오버라이딩

코틀린에서는 메서드 오버라이딩을 할 때도 메서드 앞에 open 키워드가 있는 메서드들만

오버라이딩 할 수 있습니다.

package org.mon.altong


open class Parent(a : Int) {
open fun funA() {
println("Parent funA()")
}
fun funB() {
println("ParentA funB()")
}
}

class Example(age : Int) : Parent(age){
constructor(name: String, age : Int) : this(age){
println("$name $age")
}

override fun funA() {
println("Child FunA()")
}

}

fun main(args: Array<String>) {

val ex = Example("altong", 27)
ex.funA()
ex.funB()
}




프로퍼티 또한 오버라이딩이 가능한데요. 프로퍼티에 대해서는 다음 포스팅에서 공부합니다.

오버라이딩 방법과 open 키워드가 있어야만 오버라이딩이 가능한 것은 메서드와 같습니다.


부모 클래스에 있는 멤버들을 호출할 때는 super 키워드를 사용합니다.

부모 클래스의 a 라는 변수를 호출하고 싶다면, super.a 처럼 호출하면 됩니다.

메서드라면 super.funA() 같은 방식으로요.


그리고 내부 클래스에서 외부 클래스가 상속받은 멤버를 호출하고 싶다면,

super.@외부클래스이름.멤버 처럼 호출하면 됩니다.


open class Foo() {
open fun funOA() {

}
}

class Outter : Foo() {

val aa: Int get() = 100

override fun funOA() {

}

fun funAA() {

}

inner class Inner {
fun funA() {
super@Outter.funOA()

}

}
}


추상 클래스

추상 클래스에서 abstract 멤버는 구현이 없습니다.

그리고 abstract 클래스나 멤버는 open 키워드가 필요없습니다.

추상 클래스를 상속받은 자식 클래스는 반드시 추상 클래스에 선언된 메서드를

반드시 오버라이딩해야 합니다.


abstract class AParent {
abstract fun funA()
}

class AChild() : AParent() {
override fun funA() {
print("need override")
}
}


반응형