다재다능 코틀린 프로그래밍 책으로 코틀린 스터디를 진행하면서 발표를 위해 준비했던 글입니다.
인터페이스와 추상 클래스 생성
인터페이스 만들기
interface Remote {
fun up()
fun down()
fun doubleUp() {
up()
up()
}
}
// default 키워드 없이 메소드 구현 가능, 재정의 가능
인터페이스 구현
class TV {
var volume = 0
}
// 생성자 뒤에 콜론으로 구현하고있음을 명시
class TVRemote(val tv: TV) : Remote {
override fun up() { tv.volume++ }
override fun down() { tv.volume-- }
}
컴패니언 객체와 인터페이스
interface Remote {
...
companion object {
fun combine(first: Remote, second: Remote): Remote = object: Remote {
override fun up() {
first.up()
second.up()
}
override fun down() {
first.down()
second.down()
}
}
}
}
추상클래스 생성
abstract class Animal(val name: String) {
abstract fun bark(): String
}
class Dog(name: String) : Animal(name) {
override fun bark() = "$name: 멍멍!"
}
인터페이스와 추상클래스의 차이와 선택 기준은 자바와 같다.
중첩 클래스와 내부 클래스
- 위에서 살펴봤던 TV와 TVRemote(구현 클래스)를 분리할 경우
- 장점
- TV 인스턴스 하나에 여러개의 TVRemote를 가질 수 있으니 연결 관계를 아낄 수 있다.
- TV 인스턴스와 분리된 채로 내부 상태를 가질 수 있다.
- 단점
- TV 인스턴스에 대한 참조를 추가로 가지고있어야한다.
- TV 인스턴스 내부를 활용할 수 없고 public 메소드만 활용할 수 있다.
- 장점
- 내부 클래스를 사용하면 장점을 살리고 단점을 버릴 수 있다.
- TV 인스턴스의 참조도 필요 없고 내부도 사용할 수 있게 됨.
- 코틀린은 중첩 클래스도 외부 클래스의 private 멤버에 접근X 하지만 내부 클래스를 사용하면 제약이 사라진다.
내부 클래스 생성
class TV {
private var volume = 0
val remote: Remote
get() = TVRemote()
inner class TVRemote: Remote {
override fun up() {
volume++;
}
override fun down() {
volume--
}
}
}
내부 클래스 this@, super@
- 내부 클래스 속성이나 메소드가 외부 클래스의 멤버와 이름이 일치한다면 특별한 this 표현식 사용 가능
-
${this@TV.toString()}
-
- 내부 클래스 메소드에서 TV의 베이스 클래스인 Any.toString()에 접근하고 싶다면 super 표현식 사용 가능
-
${super@TV.toString}
- 베이스 클래스로 바이패스 해서 오류가 많아지고 다형성을 깨뜨리므로 사용하지 말자.
-
getter로 익명 내부 클래스 사용하기
class TV {
private var volume = 0
val remote: Remote
get() = object: Remote {
override fun up() { volume++; }
override fun down() { volume-- }
override fun toString() = "${this@TV.toString()}"
}
override fun toString() = "TV 볼륨: $volume"
}
상속
- 코틀린 클래스는 디폴트가 final
- open이라고 명시된 클래스, 메소드만 상속 가능
- 자식 클래스는 override로 명시해줘야 한다.
- final override를 명시 후 재정의 하면 이후 서브 클래스가 해당 메소드를 재정의할 수 없다.
- val로 정의된 속성 → var, val 재정의 가능
- var로 정의된 속성 → var만 재정의 가능
- val로 재정의하면서 setter를 내부적으로 제거할 수 없기 때문
- 베이스 클래스의 private나 protected 멤버를 자식 클래스에서는 public으로 만들 수 있다.
- 반대의 경우인 베이스 클래스의 public 멤버를 자식 클래스의 private나 protected로는 만들 수 없다.
씰드 클래스
- 동일한 파일에 작성된 다른 클래스들만 sealed class 확장 가능
sealed class Card(val suit: String)
class Ace(suit: String) : Card(suit)
class King(suit: String) : Card(suit)
- sealed class의 생성자는 private으로 취급된다.
- 자식 클래스는 sealed 클래스의 싱글톤 객체가 될 수 있다.
- sealed 클래스의 객체는 생성할 수 없지만 자식 객체들은 생성할 수 있다.
enum의 생성과 사용
enum class Suit {
CLUBS, DIAMONDS, HEARTS, SPADES
}
sealed class Card(val suit: Suit)
class Ace(suit: Suit) : Card(suit)
class King(suit: Suit) : Card(suit)
- enum 메소드에 open 키워드를 붙이면 enum 인스턴스에서 open 메소드를 재정의할 수 있다.
- enum 메소드를 추상메소드로 만들 수도 있다. 각각의 인스턴스에서 추상메소드를 구현해야 한다.
'스터디 > 다재다능 코틀린 프로그래밍' 카테고리의 다른 글
10. 람다를 사용한 함수형 프로그래밍 (0) | 2021.11.29 |
---|---|
9. 델리게이션을 통한 확장 (0) | 2021.11.29 |
7. 객체와 클래스 (0) | 2021.11.29 |
6. 오류를 예방하는 타입 안전성 (0) | 2021.11.29 |
5. 콜렉션 사용하기 (0) | 2021.11.29 |