Kotlin 가변성

Kotlin 가변성

  • 불변성 : 제너릭이 설정된 객체의 주소 값을 같은 타입의 제네릭이 설정된 변수에만 담을 수 있다.
  • 공변성 : 제네릭이 설정된 객채의 주소 값을 부모 클래스 타입의 제네릭이 설정된 변수에도 담을 수 있다.
  • 반 공변성 : 제네릭이 설정된 객체의 주소 값을 자식 클래스 타입의 제네릭이 설정된 변수에도 담을 수 있다.

불변성(무변성)

 불변성 (Invariant): 기본적으로 제네릭 타입은 불변성입니다. 불변성은 타입 간에 하위 타입 관계가 없음을 의미합니다. 즉, List<String>은 List<Any>의 하위 타입도 상위 타입도 아닙니다. 이는 제네릭 타입이 완전히 독립적으로 동작하고 서로 호환되지 않는 것을 의미합니다.

fun main() {
var obj1:TestClass1<SubClass1> = TestClass1<SubClass1>()
var obj2:TestClass1<SubClass2> = TestClass1<SubClass1>() // ERROR
}

open class SuperClass1

open class SubClass1 : SuperClass1()

class SubClass2 : SubClass1()

class TestClass1<T>()

Kotlin: Type mismatch: inferred type is SubClass1 but SubClass2 was expected
Kotlin: Type mismatch: inferred type is TestClass1<SubClass1> but TestClass1<SubClass2> was expected

 클래스가 상속 관계 이더라도, 타입에는 하위 관계가 없기 때문에, 동일한 타입을 사용해야 한다. 이러한 오류는 주로 제네릭 클래스나 함수를 다룰 때 발생하며, 기대하는 제네릭 타입 매개변수와 다른 타입의 값을 할당하려고 할 때 발생한다.


공변성

 공변성은 제네릭 타입이 상속 관계에서 타입 변환을 지원하는 개념입니다. out 키워드를 사용하여 제네릭 타입 매개변수를 공변성으로 지정할 수 있습니다. 예를 들어, List<out T>는 T의 하위 타입인 U에 대해 List<U>의 하위 타입이 될 수 있습니다. 이는 제네릭 타입이 반환 타입으로만 사용되고 입력으로 사용되지 않는 경우 유용합니다.
fun main() {
var obj1:TestClass1<SubClass1> = TestClass1<SubClass1>()
var obj3:TestClass1<SuperClass1> = TestClass1<SubClass1>()
}

open class SuperClass1

open class SubClass1 : SuperClass1()

class SubClass2 : SubClass1()

class TestClass1<out T>()
out 으로 제네릭을 설정시, 부모클래스 타입으로 하위 클래스 객체를 생성 할 수 있다.

반 공변성

 반공변성은 제네릭 타입이 상속 관계에서 타입 변환을 반대로 지원하는 개념입니다. in 키워드를 사용하여 제네릭 타입 매개변수를 반공변성으로 지정할 수 있습니다. 예를 들어, Comparable<in T>는 T의 상위 타입인 U에 대해 Comparable<U>의 상위 타입이 될 수 있습니다. 이는 제네릭 타입이 입력 타입으로만 사용되고 반환 타입으로 사용되지 않는 경우 유용합니다.
fun main() {
var obj1:TestClass1<SubClass1> = TestClass1<SubClass1>()
var obj3:TestClass1<SubClass2> = TestClass1<SubClass1>()
}

open class SuperClass1

open class SubClass1 : SuperClass1()

class SubClass2 : SubClass1()

class TestClass1<in T>()
in 으로 제네릭을 설정시, 자식클래스 타입으로  클래스 객체를 생성 할 수 있다. 공변성 방식은 많이 사용하나, 반 공변성 방식은 위험하기 때문에 잘 사용하지 않는다.

객체를 생성할 때 타입을 결정하는 개념을 제네릭이라고 부르며, 상속관계에 있는 객체를 생성할 때, 타입을 지정할때 in, out 키워드를 사용해서 만들수 있다.

메서드는 동일하고 타입만 다른 메서드를 만들고 싶을 때, 많이 사용한다.


댓글

이 블로그의 인기 게시물

Intel® HAXM installation failed 해결하기

Kotlin Interface

Kotlin this, super