티스토리 뷰
본 포스팅의 내용은 [깡샘의 코틀린 프로그래밍]을 공부하고 작성자가 생각을 정리하기 위해서 작성한 글이므로 더욱 자세한 내용을 알고 싶으신 분은 [깡샘의 코틀린 프로그래밍]을 강력 추천합니다!!
1. 코틀린에서의 상속
1.1. Any 클래스
- 코틀린의 모든 클래스는 Any 클래스의 서브 클래스이다.
- 코틀린에서 클래스를 선언할 때 상위 클래스를 명시하지 않으면 기본으로 Any 클래스를 상속받는다.
- Any 클래스는 자바의 java.lang.Object 클래스와는 다르다. Any 클래스는 equals( ), toString( ) 이외의 다른 멤버들은 제공하지 않는다.
1.2. 상속을 통한 클래스 정의
- 코틀린에서 어떤 클래스를 상속받으려면, 해당 클래스 선언부에 상속 허용 여부를 결정하는 open 예약어를 사용해야 한다.
- 코틀린에서 상속 관계 표현은 콜론(:)을 이용한다.
open class Shape {
var x: Int = 0
set(value) {
if (value < 0) field = 0
else field = value
}
var y: Int = 0
set(value) {
if (value < 0) field = 0
else field = value
}
}
class Rect: Shape() {
var width: Int = 0
set(value) {
if (value < 0) field = 0
else field = value
}
var height: Int = 0
set(value) {
if (value < 0) field = 0
else field = value
}
}
2. 오버라이드
오버라이드란 상위 클래스에 정의된 프로퍼티나 함수를 하위 클래스에서 재정의하는 것이다.
2.1. 함수 오버라이드
- 함수를 하위 클래스에서 다시 정의할 수 있도록 허용하려면 함수 선언에 명시적으로 open 예약어를 추가해야 한다.
- 하위 클래스에서 상위 클래스의 함수를 재정의할 때는 함수 앞에 꼭 override 예약어를 추가해야 한다.
open class Shape {
//...
open fun print() {
println("$name : location : $x, $y")
}
}
class Rect: Shape() {
//...
override fun print() {
println("$name : location : $x, $y, width: $width, height: $height")
}
}
2.2. override 예약어
- override 예약어는 하위 클래스에서 상속받은 상위 클래스의 함수를 재정의할 때 사용한다.
- override 예약어로 정의한 함수는 자동으로 open 상태가 되어 open 예약어를 추가하지 않아도 다시 하위 클래스에서 재정의할 수 있다.
- final 예약어를 사용하여 하위 클래스에서는 자신을 재정의하지 못하도록 막을 수 있다.
2.3. 프로퍼티 오버라이드
- 하위 클래스에서 상위 클래스의 프로퍼티를 재정의하고 싶다면 같은 이름으로 다시 선언해서 사용한다.
- 프로퍼티를 오버라이드할 때는 약간의 규칙이 있는데 다음과 같다.
- 상위 클래스의 프로퍼티와 이름, 타입이 모두 같아야 함
- 상위 클래스에 val로 선언된 프로퍼티는 하위에서 val, var로 재정의 가능
- 상위에서 var로 선언된 프로퍼티는 하위에서 var로 재정의 가능 (val로는 불가)
- 상위에서 null 허용으로 선언된 경우 하위에서 null 불허로 재정의 가능
- 상위에서 null 불허로 선언된 경우 하위에서 null 허용으로 재정의 불가
- override가 명시된 프로퍼티는 open을 추가하지 않아도 하위에서 재정의할 수 있도록 허용한다.
- 상위 클래스의 프로퍼티를 재정의하면서 하위에서는 재정의하지 못하도록 막고 싶으면 final 예약어를 명시한다.
2.4. 상위 클래스 멤버 접근 (super)
- 재정의한 멤버가 있어도 때로는 상위 클래스에 정의한 멤버도 함께 이용해야할 때 super 예약어를 사용한다.
상위 멤버를 하위에 재정의해서 사용하면 되는데 다시 상위 멤버를 super로 이용할 필요가 있는가?
일반적으로 상위 클래스의 원본 함수에서는 여러 클래스에서 공통으로 처리할 로직을 작성하고, 하위 클래스의 오버라이드 함수에서는 해당 클래스만의 특징적인 로직을 작성한다.
상위클래스에서 작성한 공통으로 처리할 로직을 구현하고 하위 클래스에서 super를 사용하여 불러오는 방식으로 코드를 작성하면 코드 중복을 피할 수 있다.
3. 상속과 생성자
3.1. 상위 클래스 생성자 호출
- 상속 관계에서 생성자의 핵심 개념은 하위 클래스의 객체를 생성할 때 어떤 식으로든 상위 클래스의 생성자는 무조건 실행되어야 한다는 것이다.
- 상위 클래스와 하위 클래스간과 주 생성자와 보조 생성자 아무리 복잡하게 선언되었더라도 생성자간의 관계는 다음의 규칙을 따른다.
- 클래스의 주 생성자가 선언되어 있다면 해당 클래스의 보조 생성자에서는 주 생성자와 연결하기 위한 this( ) 구문이 추가되어야 한다.
- 객체 생성 시 어떤 식으로든 상위 클래스의 생성자는 호출되어야 한다.
3.2. 상하위 생성자의 수행 흐름
생성자가 호출되면 다음 순서로 생행된다.
- this( ) 혹은 super( )에 의한 다른 생성자 호출
- init 블록 호출
- 생성자의 { }(몸체) 영역 실행
4. 상속과 캐스팅
상속 관계에서도 캐스팅이 필요하다. 하위 객체가 상위 타입으로 표현해야 하거나 반대로 상위 타입의 객체가 하위 타입으로 표현해야 하는 경우가 발생한다.
4.1. 스마트 캐스팅
- 스마트 캐스팅이란 개발자가 코드에서 명시적으로 캐스팅을 선언하지 않아도 자동으로 캐스팅되는 것을 의미한다.
is 예약어 이용 시
- is 연산자로 타입을 확인하고 해당 타입에 해당하면 자동으로 형 변환이 발생한다.
// 함수의 매개변수 anyData는 타입이 Any였지만 anyData가 Int 타입이면 해당 타입으로 자동 형 변환
fun smartCast(anyData: Any): Int{
if (anyData is Int) return anyData * anyData
else return 0
}
상속 관계에서 스마트 캐스팅
- 하위 타입의 객체를 상위 타입에 대입할 경우 스마트 캐스팅이 일어난다.
4.2. as를 이용한 캐스팅
- 상속 관계에 있는 객체를 명시적으로 캐스팅할 때 as를 이용한다.
- 원래 하위 타입의 객체로 생성된 객체가 상위 타입으로 캐스팅되었었던 객체라면 as 연산자를 활용하여 다시 하위 타입의 객체로 변환하는 것이 가능하다.
- 애초에 상위 타입으로 생성되었던 객체는 하위 타입의 객체로 형 변환하는 것은 불가능하다.
- 하나의 상위 타입의 객체를 공유하는 두 하위 타입 객체간의 형 변환은 불가능하다.
4.3. null 허용 객체의 캐스팅(as?)
- as?를 사용하면 null 허용 객체에 정상적인 객체가 대입되면 정상적으로 캐스팅하고 null이 대입되면 null을 반환한다.
5. 접근 제한자
5.1. 접근제한자란?
- 접근 제한자란 외부에서 클래스, 생성자, 프로퍼티, 함수 등을 이용할 때 접근의 범위를 지정하고자 사용한다.
- 정보은닉과 유지보수 측면에서 접근 제한자를 적절히 이용하는 것은 중요하다.
5.2. 접근 제한자와 접근 범위
최상위 구성요소인지 클래스의 구성요소인지에 따라 접근 제한자가 약간의 차이를 보인다.
최상위 구성요소의 접근 제한자
- public : (Default) 만약 접근 제한자를 명시하지 않으면 자동으로 public을 적용. 어느 곳에서나 접근 가능
- private : 같은 파일 내에서만 접근 가능
- internal : 같은 모듈내에서만 접근 가능
- protected : 사용 불가능
클래스 멤버의 접근 범위
- public : (Default) 만약 접근 제한자를 명시하지 않으면 자동으로 public을 적용. 어느 곳에서나 접근 가능
- private : 같은 클래스 내에서만 접근 가능
- internal : 같은 모듈에 선언된 클래스에서만 접근 가능
- protected : private + 서브 클래스에서만 접근 가능
5.3. 프로퍼티와 생성자의 접근 제한
프로퍼티와 접근 제한자
- 외부에서 데이터를 사용할 수는 있어도, 변경하지는 못하게 만들어야 할 때가 있다.
- 프로퍼티의 set( ) 함수를 private으로 재정의한다.
- 프로퍼티의 get( ), set( )을 직접 작성하여 접근 제한자를 다르게 설정할 때 다음의 규칙을 따라야 한다.
- get( ) 함수의 접근 제한자는 프로퍼티의 접근 제한자와 항상 같다.
- set( ) 함수의 접근 제한자는 프로퍼티의 접근 제한자와 다르게 설정할 수 있지만, 접근 범위를 넓혀서 사용할 수는 없다.
- public > internal/protected > private
생성자와 접근 제한자
- 생성자는 protected로 지정할 수 없다.
- 주 생성자에 접근 제한자를 지정하려면 constructor 키워드를 생략할 수 없다.
5.4. 상속 관계와 접근 제한자.
- open과 private는 함께 사용할 수 없다. => 어찌보면 당연하다. 상속 받으려면 최소 protectd여야 한다.
- 하위 클래스에서 상위 멤버를 오버라이드할 때 접근 범위를 줄일 수 없다.
자바 vs. 코틀린
- 코틀린의 클래스, 변수, 함수는 기본적으로 final이 적용되어 상속이나 오버라이딩이 불가능하며, 상속이나 오버라이딩을 허용하려면 open으로 선언해야 한다.
- 코틀린에서는 객체를 명시적으로 캐스팅하려면 as를 이용한다.
- 코틀린에서 기본 접근 제한자는 public이다.
반응형
'Programming > 코틀린(Kotlin)' 카테고리의 다른 글
[코틀린] 10. 추상 클래스와 인터페이스 (feat. 깡샘) (0) | 2021.04.12 |
---|---|
추상 클래스와 인터페이스의 사용 목적 (0) | 2021.04.12 |
[코틀린] 08. 프로퍼티 (feat. 깡샘) (0) | 2021.04.11 |
[코틀린] 07. 클래스 (feat. 깡샘) (0) | 2021.04.08 |
[코틀린] 06. 흐름 제어 구문과 연산자 (feat. 깡샘) (0) | 2021.04.05 |
댓글