///////
Search
👩🏻

Java Generic의 반공변, 공변, 무공변은 무엇인지 설명해주세요.

핵심
Java의 제네릭은 기본적으로 무공변의 성질을 가지고 있어서 전달받은 딱 그 타입으로만 서로 캐스팅이 가능하다.
하지만 이는 코드를 유연하지 않게 만들기 때문에, 와일드 카드 타입을 이용해서 변성을 이용할 수 있게 했다.
제네릭의 공변상한 경계 와일드카드를 이용하여 클래스를 상속한 자손들을 한정으로 업캐스팅이 가능하다는 성질이고,
(parent = child; : IntegerObject의 하위 타입일 경우, C<Integer>C<? extends Object>의 하위 타입이 되는 것)
제네릭의 반공변하한 경계 와일드카드를 이용하여 특정 클래스의 조상 클래스들을 한정으로 다운캐스팅이 가능하다는 성질이다.
(child = parent; : ObjectInteger의 상위 타입일 경우, C<Object>C<? super Integer>의 하위 타입이 되는 것)

변성(Variance) 이란? / 제네릭의 무공변

반공변, 공변, 무공변은 변성이라는 개념안에서 나온 단어들이다.
JAVA뿐만 아니라 이 변성은 다른 프로그래밍 언어를 설명할 때도 나오는 개념으로
타입의 계층 관계에서 서로 다른 타입 간에 어떤 관계가 있는지 나타내는 지표이다.
공변 : S 가 T 의 하위 타입이면,
S[] 는 T[] 의 하위 타입이다.
List<S> 는 List<T> 의 하위 타입이다.
반공변 : S 가 T의 하위 타입이면,
T[] 는 S[] 의 하위 타입이다. (공변의 반대)
List<T> 는 List<S> 의 하위 타입이다. (공변의 반대)
무공변 / 불공변 : S 와 T 는 서로 관계가 없다.
List<S> 와 List<T> 는 서로 다른 타입이다.
// 공변성 Object[] Covariance = new Integer[10]; // 반공변성 Integer[] Contravariance = (Integer[]) Covariance; // 공변성 ArrayList<Object> Covariance = new ArrayList<Integer>(); // 반공변성 ArrayList<Integer> Contravariance = new ArrayList<Object>();
Java
복사
제네릭은 기본적으로 무공변이다. 따라서 제네릭은 전달받은 딱 그 타입으로만 서로 캐스팅이 가능하다.
public static void main(String[] args) { MyList<Number> list; collection<Integer> intList = Array.asList(1,2,3,4,5); list = new MyList<>(intList); // 컴파일 에러 발생. // 🔴 제네릭은 무공변이기 때문에, <Number>로 선언하였으면 Number 객체만 들어가야 한다. // Inteager 가 자바언어에서 Number의 하위 객체여도 말이다.
Java
복사
하지만 이는 자바의 다형성에 어울리지 않는 듯 보인다.
그래서 제네릭은 한정적 와일드카드 타입 기능을 통해 공변을 제공하기도 한다.

와일드 카드 타입을 활용한 제네릭

와일드카드
네이밍
설명
변성
<?>
Unbounded wildcards 비한정적 와일드 카드
제한 없음 (모든 타입이 가능)
<? extends U>
Upper Bounded Wildcards 상한 경계 와일드카드
상위 클래스 제한 (U와 그 자손들만 가능)
공변성 적용
<? super U>
Lower Bounded Wildcards 하한 경계 와일드카드
하위 클래스 제한  (U와 그 조상들만 가능)
반공변성 적용
상한 경계 와일드카드
ArrayList<? extends Object> parent = new ArrayList<>(); ArrayList<? extends Integer> child = new ArrayList<>(); parent = child; // 공변성 (제네릭 타입 업캐스팅)
Java
복사
IntegerObject의 하위 타입일 경우, C<Integer>C<? extends Object>의 하위 타입이 되는 것.
하한 경계 와일드카드
ArrayList<? super Object> parent = new ArrayList<>(); ArrayList<? super Integer> child = new ArrayList<>(); child = parent; // 반공변성 (제네릭 다운캐스팅)
Java
복사
ObjectInteger의 상위 타입일 경우, C<Object>C<? super Integer>의 하위 타입이 되는 것.
와일드카드 타입을 통해 타입 매개변수 지점에 변성을 정하는 자바의 방식을 사용지점 변성(use-site variance) 이라 한다.
자바와 같이 JVM을 이용하는 코틀린에서도 사용자 지점 변성을 제공한다.
참조