[kotlin] Generic

sundays·2022년 9월 9일
0

kotlin

목록 보기
3/19

Generic

제네릭(Generic)은 클래스 내부에서 사용할 자료형을 나중에 인스턴스를 생성할 때 확정된다
자료형의 객체들을 다루는 메서드나 클래스에서 컴파일 시간에 자료형을 검사해 적당한 자료형을 선택할 수 있도록 하기 위해서 제네릭이 등장

open class Parent

class Child: Parent()

class Cup<T>

fun main() {
    val obj1:Parent = Child()
    //val obj2:Child = Parent() // 에러 child 객체 obj2 는 parent 로 변환 불가

    //val obj3: Cup<Parent> = Cup<Child>() // 에러
    //val obj4:Cup<Child> = Cup<Parent>() // 에러

    val obj5 = Cup<Child>();
    val obj6: Cup<Child> = obj5
}

Generic Function

fun <형식 매개변수[...]> 함수명(매개변수: <매개변수 자료형>[, ...]): <반환 자료형>
  • 자료형의 결정은 함수가 호출될 때 컴파일러가 자료형 추론
  • 반환자료형과 매개변수 자료형에 사용 할 수 있다
fun <T> genericFunc(arg: T): T? { ... } // 매개변수와 반환 자료형에 형식 매개변수 T가 사용됨

fun <K, V> put(key: K, value: V): Unit { ... } // 형식 매개변수가 여러 개인 경우

가변성

  • 형식 매개변수가 클래스 계층에 어떤 영향을 미치는지 정의
  • 하위 클래스는 상위클래스가 수용
    • 하위 자료형은 상위 자료형으로 자연스럽게 형 변환이 이루어짐
  • 가변성의 3가지 유형

1. 공변성(covariance)

  • 형식 매개변수 사이의 하위 자료형 관계가 성립
  • 하위 자료형 관계가 그대로 인스턴스 자료형 사이의 관게로 이어지는 경우
  • out 키워드를 사용해 정의

2. 반공변성(contravariance)

  • 자료형의 상하 관계가 반대
  • 하위 클래스의 자료형을 상위 클래스의 자료형이 허용

3. 무변성(invariance)

  • 자료형 사이의 하위 자료형 관계가 성립하지 않음
  • 코틀린에서 지정 해주지 않으면 기본적으로 무변성

자료형 프로덕션

선언 지점 변성(declaration-site variance)

class Box<in T: Animal>(var item: T)
  • 클래스를 선언하면서 클래스 자체에 가변성을 지정하는 방식으로 클래스에 in/out을 지정
  • 선언하면서 지정하면 클래스의 공변성을 전체적으로 지정하는 것이 되기 때문에 클래스를 사용하는 장소에서는 따로 자료형을 지정해 줄 필요가 없어 편리

사용 지점 변성(use-site variance)

class Box<T>(var item: T)

...

fun <T> printObj(box: Box<out Animal>) {
    val obj: Animal = box.item // item의 값을 얻음(get)
    box.item = Animal() // 오류
    println(obj)
}
  • 메서드 매개변수에서 또는 제네릭 클래스를 생성할 때와 같이 사용 위치에서 가변성을 지정
  • 형식 매개변수가 있는 자료형을 사용할 때마다 해당 형식 매개변수를 하위 자료형이나 상위 자료형 중 어떤 자료형으로 대체할 수 있는지를 명시

reified 자료형

fun <T> myGenericFun(c: Class<T>)
  • T 자료형은 실행 시간에 삭제
  • 컴파일 시간에는 접근 가능하나 함수 내부에서 사용하려면 위의 코드에서 함수의 매개
    변수를 넣어 c: Class처럼 지정해야만 실행 시간에 사라지지 않고 접근
inline fun <reified T> myGenericFun()
  • reified 로 형식 매개변수 T를 지정하면 실행 시간에 접근 가능
  • inline 함수에서만 사용 할 수 있다
    • 컴파일러가 복사해 넣을 때 실제 자료형을 알 수 있기 때문에
      실행 시간에도 사용할 수 있게 됨

Class 와 KClass

Class

  • .class 형태로 반환받는 객체
  • Class라는 클래스는 원본 클래스에 대한 많은 메타 데이터를 가짐

Object::class

  • 코틀린의 표현 방법으로 KClass를 나타낸다
package part2.chap04.section1

fun main() {
    val result = getType<Float>(10)
    println("result = $result")
    val result2 = getType<Int>(1)
    println("result2 = $result2")
    val result3 = getType<Double>(2)
    println("result3 = $result3")
}

inline fun <reified T> getType(value: Int) :T {
    println(T::class) // 실행 시간에 삭제되지 않고 사용 가능
    println(T::class.java)

    return when (T::class) { // 받아 들인 제네릭 자료형에 따라 반환
        Float::class -> value.toFloat() as T
        Int::class -> value.toInt() as T
        else -> throw IllegalStateException("${T::class} is not supported")
    }
}
[결과 화면]
class kotlin.Float
class java.lang.Float
result = 10.0
class kotlin.Int
class java.lang.Integer
result2 = 1
class kotlin.Double
class java.lang.Double
Exception in thread "main" java.lang.IllegalStateException: class kotlin.Double is not supported
	at part2.chap04.section1.ReifiedGenericKt.main(ReifiedGeneric.kt:42)
	at part2.chap04.section1.ReifiedGenericKt.main(ReifiedGeneric.kt)

Process finished with exit code 1
profile
develop life

0개의 댓글