본문 바로가기
Kotlin

[깡샘의 코틀린 프로그래밍] 정리 17 - Variance

by 들풀민들레 2018. 3. 2.

본 글은 [깡샘의 코틀린 프로그래밍 - 루비페이퍼] 의 내용을 발췌한 것입니다.

좀더 자세한 내용은 책을 통해 확인해 주세요.

 

 

 

17장. 제네릭

 

17.3.1. Variance란?

 

제네릭에서 Variance (가변, 공변 등으로 해석되지만 이 책에서는 Variance로 칭하겠습니다)란 타입과 관련된 이야기입니다. 상하위 관계에서 타입 변형과 관련 있습니다. 우선 제네릭의 Variance를 이해하기 위해 클래스의 상하위 관계에 대해 살펴보겠습니다.

 

 

Super라는 클래스가 있고 이 클래스를 상속받아 Sub 클래스를 선언했다고 가정해 보겠습니다. 그러면 Sub 타입의 객체를 Super 타입에 대입하고 다시 Super 타입으로 캐스팅할 수 있습니다

 

01 package seventeen_three_one

02

03 open class Super {

04   open fun sayHello() {

05     println("i am super sayHello...")

06   }

07 }

08

09 class Sub: Super(){

10   override fun sayHello() {

11     println("i am sub sayHello....")

12   }

13 }

14

15 fun main(args: Array<String>) {

16   val obj: Super = Sub()

17   obj.sayHello()

18

19   val obj2: Sub = obj as Sub

20   obj2.sayHello()

21 }

 

위 소스 16번 줄을 보면 Sub( ) 함수로 생성한 객체가 캐스팅되어 Super 타입의 객체에 대입되었고, 다시 19번 줄에서 Sub 타입으로 캐스팅되었습니다. 컴파일 에러도 발생하지 않고 잘 실행됩니다. 그렇다면 클래스의 상하위 관계에 의한 캐스팅이 제네릭에도 가능할까요?

 

 

Sub 클래스는 Super의 하위 클래스입니다. 따라서 Sub 객체를 Super 타입으로 표현할 수 있지만, 제네릭은 타입이지 클래스가 아니므로 MyClass<Sub>로 명시한 타입을 MyClass<Super> 타입에 대입할 수는 없습니다.

 

01 package seventeen_three_one_one

02

03 open class Super

04

05 class Sub: Super()

06

07 class MyClass<T>

08

09 fun main(args: Array<String>) {

10   val obj = MyClass<Sub>()

11

12   val obj2: MyClass<Super> = obj //에러

13 }

 

07번 줄의 MyClass는 <T>를 이용하여 형식 타입으로 선언했습니다. 그리고 10번 줄에서 MyClass<Sub>로 Sub 타입을 지정하여 객체를 생성했습니다. 여기까지는 별문제가 없습니다. 그런데 12번 줄에서 MyClass<Sub>로 생성한 객체를 다시 MyClass<Super> 타입에 대입하려고 하면 컴파일 에러가 발생합니다. Sub는 Super의 하위 클래스이지만 MyClass<Sub>는 MyClass<Super>의 하위 클래스가 아니기 때문입니다.

 

 

Sub와 Super는 클래스이면서 타입으로도 이용되므로 타입 캐스팅이 가능하지만, MyClass<Sub>와 MyClass<Super>는 그 자체가 클래스가 아닙니다. 단지, 제네릭을 이용하여 타입으로만 이용됩니다. 따라서 일반 클래스의 상하위 관계에 의한 캐스팅은 불가능합니다.

 

그렇다면 MyClass<Sub>로 선언된 객체를 MyClass<Super>에 대입할 수는 없을까요? 그렇게 하려면 특별한 처리를 해주어야 합니다. 이를 제네릭의 Variance라고 합니다. 이를 위해 out과 in이라는 어노테이션을 제공합니다. out과 in을 이용하지 않으면 기본으로는 제네릭 타입의 형 변환이 불가능합니다. 이를 invariance (무공변)라고 합니다.