실무 프로젝트로 배우는 Kotlin & Spring/코틀린 고급

제네릭

webmaster 2022. 10. 16. 22:53
728x90
fun main() {
    //제네릭을 사용한 클래스의 인스턴스를 만드려면 타입아규먼트를 제공
    //val generics = MyGenerics<String>("테스트")
    //val generics = MyGenerics("테스트") // 컴파일러가 제네릭 타입이 String 인것을 알기 때문에 생략 가능

    
    //변수의 타입에 제네릭을 사용한 경우
    val list1: MutableList<String> = mutableListOf()
    //타입아규먼트를 생성자에서 추가
    val list2 = mutableListOf<String>()

    //스타 프로젝션을 사용
    val list3: List<*> = listOf<String>("테스트")
    val list4: List<*> = listOf<Int>(1,2,3,4)
    

}
  • 코틀린의 클래스는 자바와 마찬가지로 타입 파라미터를 가질 수 있다.
  • 제네릭을 사용한 클래스의 인스턴스를 만들려면, 타입 아규먼트를 제공하면 된다.
    • 인자를 통해 타입 추론이 가능한 경우 타입 아규먼트 생략 가능
    • 타입 추론이 가능하기 때문에 변수의 타입에 타입 아규먼트를 추가해도 되고 그렇지 않은 경우 타입 아규먼트를 생성자에서 추가해도 된다.
  • 안전하게 사용하고 싶은 경우 어떤 타입이든 받을 수 있는 스타 프로젝션을 사용하면 된다.

변성

  • 제네릭에서 파라미터화 된 타입이 서로 어떤 관계에 있는지를 설명하는 개념으로 크게 공변성, 반 공변성, 무 공변성으로 나뉜다.
  • 이펙티브 자바에선 공변성과 반 공변성을 설명할 때, PECS(Producer-Extends, Consumer-Super) 규칙을 언급한다.
    • 공변성은 자바 제네릭의 extends 키워드이고 코틀린에서는 out
    • 반 공변성은 자바 제네릭의 super 키워드이고, 코틀린에서는 in
class MyGenerics<out T>(val t: T){

}

class Bag<T>{
    fun saveAll(
        to: MutableList<in T>,
        from: MutableList<T>,
    ){
        to.addAll(from)
    }
}
fun main(){
	//변성 : 제네릭에서 파라미터화된 타입이 어떤 관계가 있는지를 설명하는것
    //PECS : (Producer-Extends, Consumer-Super)
    //공변성은 자바 제네릭의 extends, 코틀린에서는 out
    //반공변성은 자바 제네릭의 super, 코틀린에서 in

    val generics = MyGenerics<String>("테스트")
    //MyGeneric<String> 이 MyGeneric<CharSequence> 보다 상위 타입으로 공변성을 사용하여 구현할 수 있다
    val charGenerics: MyGenerics<CharSequence> = generics //컴파일 오류 발생

    val bag = Bag<String>()
    //반공변성 사용 : 제네릭을 소비하는 측이 되므로 반공변성이다(Consumer)
    bag.saveAll(mutableListOf<CharSequence>("1", "2"), mutableListOf<String>("3", "4")) //컴파일 오류

    //무공변성 : 실제 String은 CharSequence는 계층 구조이지만, 이걸 제네릭화한 mutableList<String>과 mutableList<CharSequence>는 아무 관계가 아닌것

}
  • 특정 상황에서 공변성이 필요하므로 공변성 키워드인 out을 통해 해결한다.
    • CharSequence가 String의 상위 타입일 때, MyGenerics<CharSequence>가 MyGenerics<String>의 상위 타입이므로 공변성이다.
  • 특정 상황에서 반 공변성이 필요하므로 반공변성 키워드인 in을 사용해 상위 타입도 전달받을 수 있도록 한다.
    • String이 CharSequnce의 하위 타입일 때, Bag<String>가 Bag<CharSqequnce>의 상위 타입이 되므로 반 공변성이다.
  • 기본은 무 공변성으로 in, out 어떤 것도 지정하지 않은 경우
    • String은 CharSequence의 하위 타입이지만, MyGeneric<String>은 MyGeneric<CharSequence>와 아무 관계도 아니다
728x90

'실무 프로젝트로 배우는 Kotlin & Spring > 코틀린 고급' 카테고리의 다른 글

페어와 구조분해할당  (0) 2022.10.16
지연 초기화  (0) 2022.10.16
확장 함수  (0) 2022.10.09
실드 클래스  (0) 2022.10.09
싱글톤과 동반객체  (0) 2022.10.09