코틀린 인터페이스 기본
- 자바 8 의 인터페이스와 유사함
- 인터페이스 내에 추상 메서드 + 구현이 있는 메서드( 자바 디폴트 메서드 ) 도 포함이 가능하다.
- 하지만, 인터페이스에는 상태를 나타내는 필드를 포함할 수 없음.
인터페이스 정의 및 구현
interface Clickable {
fun click()
}
click
이라는 추상 메서드를 가진Clickable
인터페이스를 정의함.- 해당 인터페이스를 구현하는 모든 클래스는
click
메서드에 대한 구현을 제공해야함
- 해당 인터페이스를 구현하는 모든 클래스는
class Button : Clickable {
override fun click() {
println("I was clicked")
}
}
Button
클래스는Clickable
인터페이스를 구현하고 click 메서드를 오버라이드
- 코틀린에서는
override 키워드
를 사용하여- 상위 클래스나 인터페이스의 메서드를 오버라이드한다는 것을 명시한다.
디폴트 구현이 있는 인터페이스 메서드
interface Clickable {
fun click()
fun showOff() = println("I'm clickable!")
}
- 코틀린 인터페이스에서 메서드에 디폴트 구현이 가능
- 특별한 키워드 필요 없음
인터페이스 충돌 해결
두 인터페이스가 동일한 디폴트 구현을 가진 메서드를 제공
- 해당 메서드를 구현하는 클래스는
명시적으로 메서드를 오버라이드해야함
interface Clickable {
fun click()
fun showOff() = println("I'm clickable!")
}
interface Focusable {
fun showOff() = println("I'm focusable!")
}
class Button : Clickable, Focusable {
override fun click() = println("I was clicked")
override fun showOff() {
super<Clickable>.showOff()
super<Focusable>.showOff()
}
}
호환성 및 디폴트 메서드 구현
- 코틀린은
자바 6
와 호환되도록 설계되었으며,- 디폴트 메서드를 지원하지 않는 자바 버전에서는
인터페이스의 디폴트 메서드 구현을 정적 메서드로 가지는 별도의 클래스를 생성
합니다.
- 디폴트 메서드를 지원하지 않는 자바 버전에서는
- 코틀린 1.5부터는
- 코틀린 컴파일러가
자바 인터페이스의 디폴트 메서드를 자동으로 생성
하게 되었음
- 코틀린 컴파일러가
인터페이스 사용 및 기반 클래스 메서드 오버라이드
- 인터페이스는 추상 메서드의 선언과 메서드 구현을 모아두는 집합체입니다.
- 클래스는 인터페이스를 구현하여 인터페이스에 정의된 추상 메서드를 구체화
open, final, abstract 변경자
기본적으로 final
- 자바에서 명시적으로
final
로 금지하지 않으면 모든 클래스를 상속이 가능하다.- 해당 사항은..
- 기반 클래스의 변경시 하위 클래스의 동작이 예기치 않게 바뀌는
취약한 기반 클래스
문제를 야기할 수 있음.
- 기반 클래스의 변경시 하위 클래스의 동작이 예기치 않게 바뀌는
- 해당 사항은..
- 코틀린에서는 해당 문제를 해결하기 위해, 클래스와 메서드를 기본적으로
final
로 설정한다.
- 어떠한 클래스에 대한 상속을 허용하려면, 클래스 앞에
open
변경자를 붙여야 한다.
- 오버라이드를 허용하고 싶은 메서드나 프로퍼티에도
open
변경자를 붙여야 한다.
예시
open class RichButton : Clickable {
fun disable() {} // final
open fun animate() {} // open
override fun click() {} // open
}
RichButton
- open 이므로 상속가능
disable
final
이므로 오버라이드가 불가능하다.
animate
open
이므로 오버라이드가 가능하다.
click
override
…Clickable
메서드 오버라이드. 슈퍼클래스가 open 이겟죠
오버라이드 금지
open class RichButton : Clickable {
final override fun click() {} // final
}
- click() 함수 오버라이드 금지
스마트 캐스트
- 클래스의 기본적인 상속 가능 상태를
final
로 설정하면 스마트 캐스트가 가능하다.
- 스마트 캐스트는 타입 검사 뒤에 변경될 수 없는 변수에만 적용이 된다.
- 프로퍼티는 기본적으로
final
이므로 대부분 스마트 캐스트에 활용할 수 있습니다.- 예시
open class Animal { open fun speak() {} } class Dog : Animal() { override fun speak() { println("멍멍") } } class Cat : Animal() { override fun speak() { println("야옹") } } fun main() { val animal: Animal = Dog() // Animal 타입 변수에 Dog 객체 할당 if (animal is Dog) { // animal이 Dog 타입인지 검사 val dog = animal // animal을 Dog 타입으로 안전하게 캐스팅 dog.speak() // Dog 객체의 speak() 메서드 호출 } else { println("animal은 Dog 타입이 아닙니다.") } } //멍멍
- Animal 클래스는 기본적으로 final 이고,
open
키워드 사용으로 상속이 허용된 상태이다.
- 위 코드에서
animal
변수는Animal
타입으로 선언되었지만
- 실제로는
Dog
객체를 참조한다.
-
if (animal is Dog)
조건문에서animal
이Dog
타입인지 검사하고,
- 이 검사가 참이면 컴파일러는
animal
을Dog
타입으로스마트 캐스트
합니다.
- 그 결과
animal.speak()
를 호출할 때Dog
클래스의speak()
메서드가 호출됩니다.
- 여기서
animal
변수는val
로 선언되어 있으므로 변경 불가능하며- 이는 스마트 캐스트가 가능한 조건 중 하나!
- Animal 클래스는 기본적으로 final 이고,
- 예시
추상 클래스
- abstract 클래스나 메서드는 인스턴스화할 수 없음
- 반드시 하위 클래스에서 구현해야함
- abstract 멤버는 항상 open이므로 open을 명시할 필요가 없다.
예시
abstract class Animated {
abstract fun animate() // 반드시 오버라이드해야 함
open fun stopAnimating() {} // open이므로 오버라이드할 수 있음
fun animateTwice() {} // final이므로 오버라이드할 수 없음
}
인터페이스
- 인터페이스 멤버는 항상
open
이며final
로 변경할 수 없다.
- 인터페이스 멤버에게 본문이 없으면 자동으로 추상 멤버가 된다.
abstract
키워드를 명시할 필요가 없다.
표 4.1 클래스 내에서 상속 제어 변경자의 의미
변경자 | 이 변경자가 붙은 멤버는... | 설명 |
final | 오버라이드할 수 없음 | 클래스 멤버의 기본 변경자 |
open | 오버라이드할 수 있음 | 반드시 open 을 명시해야 오버라이드 가능 |
abstract | 반드시 오버라이드해야 함 | 추상 클래스의 멤버에만 사용 가능 |
override | 상위 클래스나 상위 인스턴스의 멤버를 오버라이드하는 중 | 오버라이드하는 멤버는 기본적으로 open |
가시성 변경자
protected 변경자
- 선언이 해당 선언을 포함하는 클래스와 해당 클래스를 상속받은 하위 클래스 내에서만 접근이 가능하다.
- 자바에서는 같은 패키지 내의 다른 클래스에서 접근이 가능했는데
- 코틀린에서는 조금 더 명확한 의미를 부여가능하도록 변경됨
코틀린과 자바 가시성 차이
- 코틀린의 public, protected, private 변경자는 자바 바이트코드에서도 유지
internal
변경자는 ⇒자바에선 없음
|| 바이트코드 상에서는public
으로 컴파일됩니다.
- 코틀린 컴파일러는
internal 멤버의 이름을 변경하여 자바 코드에서의 접근을 어렵게 만듭니다.
- 예를 들어
// Kotlin internal fun doSomethingInternal() { println("This is an internal function.") }
해당 함수를 컴파일시 → 이름 변경
// Java (컴파일된 코틀린 코드) public void doSomethingInternal$production_sources_for_module() { System.out.println("This is an internal function."); }
- 이름이 이런 식으로 변경된다면 자바 코드에서 원래 함수 이름으로 접근은 불가능해짐.
- 물론 변경된 함수를 호출하려면 변경된 이름을 정확하게 알아야함.
아는 경우는 접근이 가능해질 수 있긴합니다
- 예를 들어
- 코틀린에서는 외부 클래스가 내부 클래스나 중첩된 클래스의 private 멤버에 접근할 수 없다.
- 예를 들어
class Outer { private val outerPrivate = "Outer Private" // 중첩된 클래스 (static nested class와 유사) class Nested { private val nestedPrivate = "Nested Private" fun accessNestedPrivate() = nestedPrivate } // 내부 클래스 (non-static nested class와 유사) inner class Inner { private val innerPrivate = "Inner Private" fun accessInnerPrivate() = innerPrivate } fun accessMembers() { val nested = Nested() // println(nested.nestedPrivate) // 오류: private 멤버에 접근할 수 없음 val inner = Inner() // println(inner.innerPrivate) // 오류: private 멤버에 접근할 수 없음 } }
- 의 얘기입니다.
- 접근이 가능하면 캡슐화를 저해하는 행위라고 생각되네요
- 의 얘기입니다.
- 예를 들어
Uploaded by N2T
'코틀린 > 코틀린인액션' 카테고리의 다른 글
[KOTLIN] 클래스 초기화 : 주 생성자와 초기화 블럭 (0) | 2024.02.21 |
---|---|
[KOTLIN] 봉인된 클래스(sealed class) : 클래스 계층의 확장 제한 (0) | 2024.02.19 |
[KOTLIN] 로컬 함수와 확장 (0) | 2024.02.09 |
[KOTLIN] 컬렉션의 처리 (0) | 2024.02.09 |
[KOTLIN] 문자열과 정규 (0) | 2024.02.09 |