Kotlin in Action 계속 공부중..
코틀린의 인터페이스는 Java 8 인터페이스와 비슷하다.
추상메서드 뿐만 아니라 구현이 있는 메서드(자바의 디폴트 메서드와 비슷)도 정의할 수 있다.
interface Clickable{
fun click()
}
class Button : Clickable {
override fun click() = println("click!")
}
자바에서는 extends, implements 키워드를 쓰지만, 코틀린에서는 :
콜론으로 다 처리한다.
다만 클래스는 뒤에 괄호()가 붙고(괄호안에는 생성자용 파라미터), 인터페이스는 붙지 않는다.
자바와 마찬가지로 클래스는 인터페이스를 원하는 만큼 구현 가능하지만, 클래스는 하나만 상속가능하다.
override
: 자바에서는 @Override 애너테이션을 쓰지만 코틀린에서는 변경자로 메서드 앞에 반드시 써야한다.
인터페이스에서 디폴트 메서드를 정의할 경우 구현하는 클래스에서 새로운 동작을 정의하거나, 정의를 생략해서 그대로 사용할 수 있다.
인터페이스 2개를 상속하는 클래스에서 중복된 이름의 디폴트 메서드가 있을 경우 super<인터페이스명>.메서드명 으로 상위 타입 메서드를 구현해야한다.
취약한 기반 클래스(fragile base class) 문제
Java에서는 final이 아닌 모든 클래스는 상속이 가능하다.
상속 시, 기반 클래스가 변경될 시 하위 클래스의 동작이 예기치 않게 바뀔 수 있다.
모든 기반 클래스 변경 시 하위클래스를 미리 파악하는 것은 힘드므로,
[Effective Java]에서는 상속을 위한 설계와 문서를 갖추거나 아니면 상속을 금지하라 는 조언이 있다.
코틀린에선 기본적으로 모든 클래스와 메서드가 final
이다.
그러므로 클래스의 상속을 허용하려면 open
변경자를 붙여야 한다.
오버라이드를 허용할 메서드나 프로퍼티도 open
을 붙여야 한다.
이미 오버라이드 한 메서드는 open 상태이다. 하지만 이 메서드를 오버라이드 다시 금지하려면 final
을 메서드에 명시하면 된다.(final override fun ~)
abstract class Animated { // 추상크랠스. 인스턴스 생성 불가
abstract fun animated() // 추상 메서드. 하위 클래스에서 반드시 구현해야
open fun stopAnimating(){ //추상클래스이지만 비추상 메서드. 오버라이드 가능
}
fun animateTwice(){ //추상클래스이지만 비추상 메서드. 오버라이드 불가능
}
}
클래스 : 기본적으로 상속이 불가능한 final. open을 붙여야 오버라이드 가능
인터페이스 : 기본적으로 모든 멤버가 open. 반드시 오버라이드 해야 함.
추상클래스 : abstract(추상)메서드는 반드시 오버라이드 해야함. 나머지 멤버는 기본적으로 final
변경자 | 상태 | 설명 |
---|---|---|
final | 오버라이드 불가 | 클래스 멤버의 기본 변경자 |
open | 오버라이드 가능 | 반드시 open을 명시해야 오바라이드 가능 |
abstract | 반드시 오버라이드 해야함 | 추상클래스 멤버에만 붙일 수 있음 |
override | 이미 오버라이드 하는 상태 | 이 멤버의 오버라이드를 금지하려면 final 붙여야함 |
코틀린에서 기본 가시성은 public
이다.internal
을 사용하는데, 이는 같은 모듈 안에서만 볼 수 있음을 뜻한다.변경자 | 클래스 멤버 | 최상위 선언 |
---|---|---|
public(기본) | 모든 곳에서 볼 수 있음 | 모든 곳에서 볼 수 있음 |
internal | 같은 모듈 안에서만 볼 수 있음 | 같은 모듈 안에서만 볼 수 있음 |
protected | 하위 클래스 안에서만 볼 수 있음 | 최상위 선언에 적용 불가능 |
private | 같은 클래스 안에서만 볼 수 있음 | 같은 파일 안에서만 볼 수 있음 |
자바처럼 코틀린에서도 클래스 안에 다른 클래스를 선언할 수 있다.
하지만 자바랑은 다르게 코틀린에선 명시적으로 요청하지 않는 한 바깥쪽 클래스 인스턴스에 대한 접근권한이 없다.
코틀린 중첩 클래스에 아무런 제어자가 붙지 않으면 자바 static 중첩 클래스와 같다.
중첩 클래스 앞에 inner
제어자를 붙이면 내부 클래스로 변경되어 바깥 클래스의 참조를 포함할 수 있다.
this@Outer
로 바깥쪽 클래스의 참조에 접근 가능하다.
클래스의 서브클래스들을 제한하는 역할을 하는 클래스
sealed
제어자를 붙인다.sealed class Shape {
class Circle(val radius: Double) : Shape()
class Square(val sideLength: Double) : Shape()
class Triangle(val base: Double, val height: Double) : Shape()
}
sealed class의 서브클래스는 반드시 같은 파일 내에서 선언되어야 한다. 서브클래스의 종류가 제한적이고 한정적임을 의미한다.
클래스 외부에 자신을 상속한 클래스를 둘 수 없다.
이를 통해 when 식 등에서 모든 경우를 고려할 수 있어 별도의 else분기가 필요없고, 특정 클래스 계층의 종류가 변경되더라도 놓치는 경우를 방지할 수 있다.