본문 바로가기

자바 언어 & 객체지향 지식

공변성, 반공변성, 무공변성에 대하여

출처: https://velog.io/@lsb156/covariance-contrav ariance

출처: https://www.youtube.com/watch?v=PtM44sO-A6g

 

 

공변성(=Covariant=함께 변한다), 반공변성(Contravariant=반대로 변한다), 무공변성(=Invariant=변하지 않는다).

 

여기서 변하고 변하지 않고의 기준은 어떤 관계(예를들면 부모 자식)가 있을때  다른 어떤 요소의(예를들면 저네릭이라는 요소)관계에 영향을  주는가의 문제임. 자바의 저네릭을 예로 들면 A가 B의 상위타입이라고 했을때 GenericType<A>는 GenericType<B>의 상위타입이 아님. 즉A가 B의 상위타입임에도 불구하고 저네릭이라는 다른 어떤 요소에서는 GenericType<A>가 GenericType<B>의 상위타입이 아니므로 변하는게 없음. 즉 저네릭은 그 자체는 무변성임.

 

Carnivore은 Tiger의 상위 타입임. 그리고 <? extends Carnivor>은 <Tiger>의 상위타입임. 즉 기본 타입의 관계가 다른 요소인 와일드카드를 사용한 저네릭에서의 관계에 영향을 줌. 따라서 이는 공변성의 예.

 

 저네릭 자체의 무공변성때문에 생기는 문제(출처 동영상 참고)를 해결하기 위해서 와일드카드<? extends Carnivore> 를 제공하여 저네릭이 더이상 무공변성이 아닌 공변성이 있게끔 한다.  하지만 공변성이 생겼다 하여 모든 문제가 해결되는게 아님. 이 남아있는 문제를 해결해 주기 위해 등장한 것이 반공변성(ContraVarient)이다.

 

Carnivore은 Tiger의 상위타입이지만 Cage<Carnivore>는 Cage<? super Tiger>의 하위타입임. 즉, 기본 타입의 관계가 다른 요소인 와일드카드를 사용한 저네릭에서의 관계에서 영향을 줌. 단!! 반대 방향으로 변함. 이것이 반공변성. 즉, 영향을 주지만 반대방향으로 영향을 준다하여 반공변성이라 한다.

 

여기서 혼동하지 말아야 할것이 왜 Cage<Carnivore>는 Cage<? super Tiger>의 하위타입 인가? 인데 쉽게 생각해서 Cage<? super Tiger> 는 Cage<Carnivore> 에 비해 범용적으로 다양한 것을 담을 수 있으므로 Cage<? super Tiger> 이 보다 범용적인 상위타입이라고 생각하면 쉽다.

공변성: 어떤 요소가 다른요소(여기서는 저네릭)에 영향을 주는것. T'가 T의 서브타입이면 C<T'>는 C<T>의 서브타입임.(자바에서는 <? extends T>의 형식으로 공변성을 만들수 있음)

 

반공변성: 어떤 요소가 다른요소에 영향을 주되 반대방향으로 영향을 주는것. T '가 T의 서브타입이면, C<T>는 C<T'>의 서브타입임.(자바에서는 <? super XXX>의 형식으로 반공변성을 만들수 있음). 아... 이래서 객체지향에서 LSP설명할때 매개변수타입은 반공변성이 제공되지 않는다면서 매개변수타입은 더 일반적인 상위타입이 와야한다고 말씀하신거구나. super를 썻다는 것은 더 상위타입을 의미하므로)

 

(바로 위의 공변성, 반(공)변성의 개념을 객체지향 설계에서배운 LSP에 적용하자면 공변성은 메서드의 반환타입과 반변성은 메서드의 매개타입 변수와 연관된다. LSP을 지키면서 하위 클래스에서 메서드를 재정의 한다는 것의 의미: 메서드의 사전 조건은 약화시키고(=반공변성=매개변수로 더 상위타입의 인자 사용 = <? super XXX>) 사후 조건은 강화(=공변성=반환타입으로 더 구체적인 하위의 타입사용= <? extends XXX> )시킨다.

 

무공변성: 한쪽이 변하는 것이 다른 쪽에 아무 영향을 주지 않는 것으로 C와 C<T'>는 관련이 없음.