본문 바로가기
깡샘 코틀린

04-2 클래스를 재사용하는 상속

by 농농씨 2023. 6. 14.

상속과 생성자

상속(inheritance)이란? 클래스를 선언할 때 다른 클래스를 참조해서 선언하는 것

코틀린에서는 어떤 클래스를 상속받으려면 선언부에 '콜론(:) 상속받을 클래스 이름' 붙여주면 됨(기존 클래스 재사용)

 

상위 클래스: 상속 관계에서 상속대상이 되는 클래스

하위 클래스: 상속 받는 클래스

클래스는 기본적으로 상속이 불가능 ➡️ 'open' 키워드 사용

상위 클래스를 상속받은 하위클래스의 생성자에서는 상위클래스의 생성자를 호출해야 함

// 클래스 상속 형식
open class Super { // open 키워드 사용하여 상속할 수 있게 됨
}
class Sub: Super() { // 콜론과 상위 클래스 이름+(매개변수 없는)생성자 함께 호출함(괄호가 생성자 그자체)
}

// 매개변수 있는 상위 클래스의 생성자 호출
open class Super(name: String) { 
}
class Sub(name: String): Super(name) { //상위 클래스의 매개변수 구성에 맞춰서 인자를 전달해야함
}

이때 상위클래스의 생성자 호출문을 꼭 클래스 선언부에 작성할 필요는 없다.

만약 하위 클래스에 보조 생성자만 있다면 상위 클래스의 생성자를 다음처럼 호출할 수 있다.

// 하위 클래스에 보조 생성자만 있는 경우 상위 클래스의 생성자 호출
open class Super(name: String) { // 매개변수 있는 상위 클래스
}
class Sub: Super { 
	// 상위 클래스를 상속은 받았지만 상위클래스의 생성자를 호출하지는 않음,
	// 하위 클래스의 주 생성자도 선언하지 않았음(따라서 자동으로 생성됨)
	constructor(name: String): super(name) { // 생성자는 클래스와 동명이면서 소문자인 함수인가???
    }
}

 

오버라이딩-재정의

상속의 최고 이점: 하위 클래스에서도 상위 클래스에서 정의된 멤버(변수, 함수) 이용 가능해짐

// 상속 관계인 두 클래스
open class Super {
	var superData = 10 
    fun superFun() {
    	println("I am superFun : $superData")
    }
}
class Sub: Super() // 본문 없이 상위 클래스를 상속만 받은 하위 클래스
fun main() {
	val obj = Sub() // 하위 클래스 객체 생성
    obj.superData = 20 // 하위클래스의 객체이지만 상위클래스를 상속받아서 상위클래스에서 정의된 속성 사용 가능해짐
    obj.superFun() // 역시나 함수도 사용 가능함
}

그런데 때로는 상의 클래스에서 정의된 멤버를 하위 클래스에서 재정의해야 할 수도 있다.

오버라이딩(overriding) : 상위 클래스에서 선언된 변수나 함수를 같은 이름으로 하위 클래스에서 다시 선언하는 것

주로 '함수'를 재정의하는 데에 사용됨(115p. 로직 언급되는데 뭔말인지 모르겠음)

// 오버라이딩 예시
open class Super { // 매개변수 없이, 생성자도 없이(자동 생성) 클래스 선언
	open var someData = 10 // 재정의할 수 있으려면 멤버변수에도 'open'키워드 사용
    open fun someFun() {
    	println("I am super class function : $someData")
    }
}
class Sub: Super() { // 상속받을 때에는 생성자 써줘야 함
	override var someData = 20 // override 키워드 사용해서 'open된' 멤버변수 재정의
    override fun someFun() { // 함수도 재정의
    	println(I am sub class function : $someData)
    }
}
fun main() {
	val obj = Sub() // 하위 클래스의 객체 생성
    obj.someFun() // 하위클래스의 함수 호출됨
}

실행결과:
I am sub class function : 20

 

접근 제한자(visibility modifier)

클래스의 멤버를 외부의 어느 범위까지 이용하게 할 것인지를 결정하는 키워드

물론 코틀린에서는 변수나 함수를 클래스로 묶지 않고 소스 파일의 최상위에 선언할 수 있으며, 이렇게 선언한 변수나 함수도 접근 제한자로 이용 범위를 지정할 수 있다.

코틀린에서 제공하는 접근 제한자: public, internal, protected, private

접근 제한자 최상위에서 이용 클래스 멤버에서 이용
public 모든 파일에서 가능 모든 클래스에서 가능
internal 같은 모듈 내에서 가능 같은 모듈 내에서 가능
protected 사용 불가 상속 관계의 하위 클래스에서만 가능
private 파일 내부에서만 이용 클래스 내부에서만 이용

public: 접근 제한자 생략했을 때 기본. 어디서든 접근 가능

internal: 같은 모듈 내에서 접근 가능. 

               모듈이란? 그래들(Gradle)이나 메이븐(Maven)과 같은 빌드 도구에서의 프로젝트 단위 또는 같은 세트

protected: 클래스의 멤버에서만 선언할 수 있고 최상위에서 사용 불가. 클래스의 멤버를 해당 클래스 내부와 그 클래스를 상속받는 하위 클래스에서 접근할 수 있게 함(open이랑 뭐가 다르지 최상위에서 직접 호출을 못한단건가->맞음)

private: 해당 클래스 내부에서만 접근 가능. 최상위에서 선언하면 해당 파일 내부에서만 접근 가능.

// 접근 제한자 사용 예시
open class Super { // 매개변수도 없고 생성자도 생략한 클래스 선언, open 키워드 사용해서 상속할 수 있게 됨
	var publicData = 10
    protected var protectedData = 20 // protected 키워드 사용해서 해당 클래스와 상속받는 클래스에서 사용가능
    private var privateData = 30 // private 키워드 사용해서 해당 클래스 안에서만 사용 가능
}
class Sub: Super() {
	fun subFun() {
    	publicData++ // 상속받아서 성공
        protectedData++ // 성공
        privateData++ // private라서 접근 제한됨. 오류!
    }
}
fun main() {
	val obj = Super() // 하위 클래스의 객체 생성
    obj.publicData++ // 성공 
    obj.protectedData++ // 오류! 하위클래스까진 사용가능하지만 그 밖인 메인함수에서 호출 불가
    obj.privateData++ // 오류! 애초에 하위클래스에서부터 접근 제한됨
}

 

'깡샘 코틀린' 카테고리의 다른 글

05-1 람다 함수와 고차 함수  (0) 2023.06.15
04-3 코틀린의 클래스 종류  (0) 2023.06.14
04-1 클래스와 생성자  (0) 2023.06.13
03 코틀린 시작하기  (0) 2023.06.06
02 안드로이드 앱의 기본 구조  (0) 2023.06.04