코틀린 (Kotlin) 인터페이스 정리
인터페이스
코틀린의 인터페이스는 자바와 같이 interface 로 시작합니다.
interface Clickable {
fun click()
}
fun click()
}
interface 를 구현할 때는 [클래스: 인터페이스] 형식으로 구현됩니다.
extends(확장)과 implements(구현) 둘 다 :(콜론) 으로 구현합니다.
코틀린은 1개의 상속과 여러개의 인터페이스를 구현할 수 있습니다.
그리고 override 변경자를 사용해서 자바의 @Override 를 대신합니다.
만약에 override 된 함수 이름과 다른 함수 이름이 중복될경우 둘중 하나는 다른 이름을 사용해야 됩니다.
//클래스 상속이나 구현은 : 으로 구분
class Button : Clickable, View { //Clickable은 interface, View 는 상속
override fun click() {
//구현시 override 필수
}
}
class Button : Clickable, View { //Clickable은 interface, View 는 상속
//구현시 override 필수
}
디폴트 메소드
자바8 에서는 디폴트 메소드인경우 default 를 붙이지만 코틀린에서는 따로 추가되는 변경자가 없이 함수를 구현하면 됩니다.
interface Clickable {
fun click()
fun showOff() = Log.d("Clickable showoff") //디폴트 메소드
}
fun click()
fun showOff() = Log.d("Clickable showoff") //디폴트 메소드
}
디폴트 메소드는 override 를 하지않은 경우 디폴트로 사용되는 함수입니다.
같은 함수 이름을 갖는 interface
디폴트 함수 이름이 같은 두개의 인터페이스를 구현해야되는 경우를 생각해봅니다.디폴트 함수 이름이 같은 이름인 인터페이스를 정의하면 컴파일 에러가 발생합니다.
interface Clickable {
fun click()
fun showOff() = Log.d("Clickable showoff")
}
interface Focusable {
fun click()
fun showOff() = Log.d("Focusable showoff")
}
class Button : Clickable, Focusable { //컴파일 에러
...
}
fun click()
fun showOff() = Log.d("Clickable showoff")
}
interface Focusable {
fun click()
fun showOff() = Log.d("Focusable showoff")
}
class Button : Clickable, Focusable { //컴파일 에러
...
}
이를 해결하기 위해서는 하위 클래스에서 super() 를 호출해야 됩니다.
showOff() 를 override 하고 블럭 안에서 super<...> 를 호출해서 상위 클래스의 메소드를 지정할 수 있습니다.
class Button : Clickable, Focusable {
//같은 이름의 메소드 override
override fun showOff() {
super<Clickable>.showOff() // 상위 함수 호출시 super<..> 를 사용할 수 있다
super<Focusable>.showOff()
}
override fun click() { //구현시 override 필수
L.d("override click()")
}
}
//같은 이름의 메소드 override
override fun showOff() {
}
override fun click() { //구현시 override 필수
}
어떤 디폴트 메소드를 실행할지 컴파일러가 판단하기 어렵기때문에 super<...> 으로 직접 지정해야 됩니다.
Clickable 의 showOff() 만 호출할 수도 있습니다.
class Button : Clickable, Focusable {
override fun showOff() {
super<Clickable>.showOff() //Clickable 만 호출 가능
}
override fun click() {
L.d("override click()")
}
}
override fun showOff() {
override fun click() {
}
디폴트 메소드가 있는 코틀린을 자바에서 사용할 경우 디폴트 메소드를 사용할 수 없기때문에 직접 구현해야 됩니다.
코틀린은 자바6 을 기반으로 하기때문입니다.
인터페이스에 프로퍼티 선언하기
코틀린에서는 인터페이스에 프로퍼티를 선언할 수 있습니다.
interface User {
//인터페이스의 프로퍼티 선언
//실제로는 getNickname() {} 이라는 비어있는 함수만 생성 됨
val nickname: String
}
//주생성자에서 프로퍼티 override 로 구현하기
//구현을하면 nickname 프로퍼티가 생성되고 생성자에서 할당이 됨
//getNickname() { return nickname } 이 자동 생성 됨
class PrivateUser(override val nickname: String) : User
//인터페이스의 프로퍼티 선언
//실제로는 getNickname() {} 이라는 비어있는 함수만 생성 됨
val nickname: String
}
//주생성자에서 프로퍼티 override 로 구현하기
//구현을하면 nickname 프로퍼티가 생성되고 생성자에서 할당이 됨
//getNickname() { return nickname } 이 자동 생성 됨
class PrivateUser(override val nickname: String) : User
주 생성자에서 인터페이스 프로퍼티를 override 하면 비어있던 interface 의 getNickname() 이 자동으로 구현됩니다.
PrivateUser 에 nickname 프로퍼티가 생성이되고 생성자로 넘겨받은 파라메터로 this.nickname = nickname 처럼 값이 할당됩니다.
그리고 getNickname() { return nickname } 으로 getter() 가 자동 생성됩니다.
커스텀 게터로 인터페이스 프로퍼티 구현하기
커스텀 게터로 interface 의 프로퍼티를 구현할 수 있습니다.
//커스텀 게터로 프로퍼티 override
class SubscribingUser(val email :String) : User {
override val nickname: String
get() = email.substringBefore("@") //nickname 을 호출할때마다 계산 됨
}
class SubscribingUser(val email :String) : User {
override val nickname: String
get() = email.substringBefore("@") //nickname 을 호출할때마다 계산 됨
}
SubscribingUser 클래스에 email 프로퍼티가 생성되고 User 인터페이스의 getNickname() 함수를 오버라이드해서 커스텀 get() 으로 email 문자열에서 nickname을 추출하여 리턴합니다.
그리고 getNickname() 은 호출할 때마다 계산 됩니다.
프로퍼티 초기화로 인터페이스 프로퍼티 구현하기
인터페이스를 상속받은 경우 인터페이스 프로퍼티를 초기화 식으로도 사용할 수 있습니다.
//프로퍼티 초기화 식으로 override
class FacebookUser(val email :String) : User {
//프로퍼티 초기화는 한번만 할당되고 그 후로는 저장된 값을 사용
override val nickname: String = email.substringBefore("@")
}
class FacebookUser(val email :String) : User {
//프로퍼티 초기화는 한번만 할당되고 그 후로는 저장된 값을 사용
override val nickname: String = email.substringBefore("@")
}
커스텀 게터로 인터페이스 프로퍼티를 구현하는 것과 프로퍼티 초기화로 구현하는 것에는 차이점이 있습니다.
- 커스텀 게터 : 매번 식을 수행
- 프로퍼티 초기화 : 최초 한번만 식이 실행되고 이후에는 저장된 값을 사용
인터페이스 프로퍼티를 상속한 경우
인터페이스 프로퍼티에 커스텀 get() 을 구현하면 상속받은 하위 클래스에서는 구현할 필요가 없습니다.프로퍼티만 있는 경우 하위 클래스에서 get()을 override 해서 구현해야 합니다.
인터페이스에서는 프로퍼티 초기화를 할 수 없습니다.
왜냐하면 값이 할당되지 않게 때문입니다.
interface User {
val email:String //구현시 오버라이드 필요
val nickname: String //구현시 오버라이드 불필요
get() = email.substringBefore("@")
//error!!! 인터페이스에서는 초기화 할수 없음
val emailId :String= email.substringBefore("@")
}
//email은 꼭 오버라이드 해야됨!!
class UserChild(override val email: String) : User
val email:String //구현시 오버라이드 필요
val nickname: String //구현시 오버라이드 불필요
get() = email.substringBefore("@")
//error!!! 인터페이스에서는 초기화 할수 없음
val emailId :String= email.substringBefore("@")
}
//email은 꼭 오버라이드 해야됨!!
class UserChild(override val email: String) : User
*개인적으로 코틀린을 공부하면서 정리한 자료입니다. 수정 사항 및 이슈가 있는 경우 메일 부탁드립니다.
초반부 주석에 View는 상속이라 써있는데 View 또한 인터페이스 아닌가요?
답글삭제