[Kotlin] 제네릭 : 타입 파라미터 소거(erasure), inline 실체화(reified)
JVM의 제네릭스는 보통 타입 소거(type erasure)를 사용해 구현되기 때문에, 실행 시점에 제네릭 클래스의 인스턴스에 타입 인자 정보가 없다.
예를 들어 ``kt List<String>`` 객체를 만들고 그 안에 문자열이 들어있더라도, 런타임에는 그 객체를 오직 ``kt List``로만 인식할 수 있다.
* 원소를 하나 얻어서 타입 검사를 수행할 수 있겠지만 여러 원소가 서로 다른 타입일 수도 있기 때문에 좋은 방법이 아니다.
* 일반적인 경우 ``kt List<String>``에는 문자열만 들어있음을 가정할 수 있는 이유는 컴파일 타임에 컴파일러가 타입 인자를 인식해 올바른 타입의 값만 리스트에 넣도록 보장해주기 때문이다.
타입 인자가 지워졌기 때문에 넘어온 타입 인자와 다른 타입 인자로 캐스팅해도 캐스팅이 된다는 점에 주의한다.
* 아래와 같은 예제는 ``kt <T: Int>``로 타입 상한을 지정해서 처리해도 되는 문제이기 때문에 그렇게 처리하는 편이 더 좋다.
```kt
fun listSum(li: List<*>) {
val intList = li as List<Int> // 캐스팅은 성공하고
println(intList.sum()) // 여기서 런타임 Exception 발생
}
>>> listSum(listOf(1, 2, 3))
6
>>> listSum(listOf("a", "b"))
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
```
런타임 타입 검사 : inline + reified (실체화한 타입 파라미터)
```kt
inline fun <reified T> isA(value: Any) = value is T
>>> isA<String>("a")
true
```
- 이게 가능한 이유는 인라인 함수는 함수 바디 코드가 함수 호출부에 삽입되기 때문에, 타입 인자가 아니라 구체적인 타입을 사용할 수 있기 때문이다.
- 자바에서는 ``kt reified``를 사용하는 ``kt inline`` 함수를 호출할 수 없다.
- 자바에서는 코틀린 인라인 함수를 다른 보통 함수처럼 호출해버려서 타입 정보가 사라지기 때문이다.
- inline reified 함수 내에서 위 예제처럼 실제 타입간 비교 등을 작성하는 경우, 자바에서 함수 호출하는 식으로 불러버리면 T타입 정보가 사라져 타입 비교가 예상과 다르게 동작하게 된다. 그래서 아예 호출하지 못하게 만든 듯.
- ``kt inline``이기 때문에, 코드 조각을 가능한 작게 유지하는 것이 좋다.
실체화한 타입 파라미터를 사용한 표준 라이브러리로는 ``kt filterIsInstance<T>()``가 있다.
```kt
>>> val li = listOf(1, "b", 3)
>>> li.filterIsInstance<Int>()
[1, 3]
```
클래스 참조(멤버 참조)와 연계해서 사용
reified 제약
- `` T``의 인스턴스를 생성할 수 없다.
- `` T``의 동반 객체 메소드를 호출할 수 없다.
- 실체화한 타입 파라미터를 요구하는 함수에 실체화하지 않은 타입 파라미터로 받은 타입을 넘길 수 없다.
- 클래스, 프로퍼티의 타입 파라미터를 ``kt reified``로 지정할 수 없다.
- ``kt inline``과 함께 사용해야 한다.
인라인 함수에만 사용할 수 있기 때문에 실체화한 타입 파라미터를 사용하는 함수는 자신에게 전달되는 모든 람다를 인라이닝한다. 그러나 람다를 인라이닝할 수 없는 상황이거나 성능 문제로 인라이닝하고 싶지 않은 경우 ``kt noinline`` 변경자를 함수 타입 파라미터에 붙여서 인라이닝을 금지할 수 있다.
'Java Stack > Kotlin' 카테고리의 다른 글
[Kotlin] thread (0) | 2017.12.31 |
---|---|
[Kotlin] 제네릭 : 변성(variance), 타입 프로젝션(type projection) (1) | 2017.12.08 |
[Kotlin] 컬렉션과 배열 (0) | 2017.12.07 |
[Kotlin] 타입 시스템 (Any, Unit, Nothing) (0) | 2017.12.06 |
[Kotlin] Nullability 관련 연산자 (0) | 2017.12.06 |