제네릭 타입 파라미터
제네릭 타입의 인스턴스를 만들기 위해서는 타입 파라미터를 구체적인 타입 인자(Type Argument)로 치환해야 한다.
List 타입이 있다고 했을 때, 명확하게 문자열을 담는 리스트
List<String>
Map 타입은 제네릭 타입변수로 Map<K, V>형태로 선언이 되어 있고, 이를 인스턴스화 할때 Map<String, Person>처럼 구체적인 타입 인자를 넘겨 인스턴스화 할수 있다.
코틀린 컴파일러의 경우, 보통 타입과 마찬가지로 타입 인자도 추론이 가능하다
val authors = listOf("John", "Sveltna")
빈 리스트의 경우, 추론할 값이 없기 때문에 직접 타입을 명시 해줘야 한다.
val authors: List<String> = emptyList();
val authors = emptyList<String>();
제네릭 함수를 호출할 때는 반드시 구체 타입으로 타입 인자를 넘겨줘야 한다.
아래 List의 slice 확장 함수를 예로 들면, 타입 파라미터 T가 수신객체와 반환 타입으로 사용된다.
타입 추론이 가능한 구체 타입으로 사용 시, 별도로 제네릭 지정이 불필요하다.
public fun <T> List<T>.slice(indices: IntRange): List<T>
타입 파라미터 선언은 클래스, 인터페이스, 클래스/인터페이스의 메소드, 확장 함수, 최상위 함수에서 선언이 가능하다.
코틀린에서는 아래와 같이 제네릭 확장 프로퍼티 선언이 가능하다.
확장 프로퍼티에 대해서만 가능하며 일반 프로퍼티는 타입 파라미터를 가질 수 없다.
val <T> List<T>.penultimate: T
get() = this[size - 2]
자바와 마찬가지로 제네릭 클래스를 확장/구현하기 위해서는 하위 클래스에서 기저 클래스의 구체 타입을 명시하거나 혹은 타입 파라미터로 받은 타입을 넘겨줘야 확장/구현이 가능하다.
class StringList: List<String> { ... }
class ArrayList<T>: List<T> { ... }
타입 파리미터는 사용할 수 있는 타입을 제한할 수 있다.
타입 파라미터에 대한 상한(upper-bound) 을 지정한다고 표현하며 제네릭 타입을 인스턴스화 하는 시점에는 상한 타입이거나 혹은 상한 타입의 하위 타입만 가능하게 된다.
상한을 지정하게 되면 해당 타입의 값은 상한 타입으로 취급이 가능하게 된다.
fun <T : Number> List<T>.sum(): T // Kotlin
```java
T sum(List list) // Java
```
두 인자값 중 큰 값을 찾는 제네릭 함수를 만든다고 할때, Comparable 인터페이스를 활용하여 코드를 작성한다고 해보자.
```kotlin
fun <T: Comparable> max(first: T, second: T): T {
// 코틀린 컴파일러에 의해 first.compareTo(second) > 0으로 변한다.
return if (first > second) first else second
}
클래스 계층 정의
인터페이스
코틀린 인터페이스 안에는 추상 메서드뿐 아니라 구현이 있는 메서드도 정의할 수 있다.
상태(필드)는 들어갈 수 없다.
//인터페이스 정의
interface Clickable {
fun click()
}
//인터페이스 구현
class Button : Clickable { //코틀린은 클래스 확장과 인터페이스 구현 모두 콜론(:)을 붙인다.
//오버라이드 표시
override fun click() = println("I was clicked")
}
자바와 마찬가지로 인터페이스는 개수 제한없이 마음대로 구현할 수 있지만, 클래스는 오직 하나만 확장할 수 있다.
상위 클래스에 있는 메서드와 시그니처가 같은 메서드를 우연히 하위 클래스에 선언하는 경우, 컴파일이 안 되기 때문에 override를 붙이거나 메서드 이름을 바꿔야 한다.
예시
interface Clickable {
fun click()
fun showOff() = println("I'm clickable!") //디폴트 구현 정의
}
interface Focusable {
fun setFocus(b: Boolean) =
println("I ${if (b) "got" else "lost"} focus.")
fun showOff() = println("I'm focusable!")
}
클래스가 구현하는 두 상위 인터페이스에 정의된 showOff 구현을 대체할 오버라이딩 메서드를 직접 제공하지 않으면 컴파일 오류가 발생한다.
이름과 시그니처가 같은 멤버 메서드에 대해 둘 이상의 디폴트 구현이 있는 경우, 인터페이스를 구현하는 하위 클래스에서 명시적으로 새로운 구현을 제공해야 한다.
```kotlin
class Button : Clickable, Focusable {
override fun click() = println(“I was clicked”)