상속과 생성자
상속(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 |