1223

[Java] 공변 본문

Java

[Java] 공변

disambur23 2022. 2. 5. 17:42

1. 공변의 성질

  • 공변(Variance)
    • A가 B의 하위 타입일 때, T<A>가 T<B>의 하위 타입
    • extends
    • Read
      • 조상관계는 공통부분이므로 적어도 조상타입은 읽을 수 있다.
      • 자식관계끼리는 읽을 수 없다.
    • Write
      • 어떠한 경우에도 불가능하다.
  • 반공변(Contravariance)
    • A가 B의 하위 타입일 때, T<B>가 T<A>의 하위 타입
    • super
    • Read
      • 불가능
    • Write
      • 대입 연산자 오른쪽 제네릭이 오른쪽 제네릭 타입과 같을 때만 가능
      • List<? super Integer> same = new ArrayList<Integer>();
  • 무공변(Invariance)
    • A가 B의 하위 타입일 때, T<A>와 T<B>가 아무런 관계가 없음

 

2. 공변, 반공변의 필요성

 

자바 클래스들의 관계

 

Object obj = new Object();
Object num = new Number();
Object str = new String():
Object inte = new Integer();

위의 코드는 공변관계가 당연히 성립한다. 하지만, 다음의 코드를 보자.

 

List<Object> obj = new ArrayList<Object>();
// List<Object> num = new ArrayList<Number>(); 에러
// List<Object> str = new ArrayList<String>(); 에러
// List<Object> inte = new ArrayList<Integer>(); 에러

제네릭은 대입 연산자 좌우의 제네릭 타입이 일치해야 하므로 에러가 난다.

이런 이유 때문에 공변이 필요한 것이다.

 

와일드카드와 공변 키워드 extends를 이용한 공변

List<? extends Number> num = new ArrayList<Number>(); 
List<? extends Number> numInt = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> numDou = new ArrayList<Double>();  // Double extends Number

이렇게 되면 에러가 나지 않고 제네릭을 사용할 수 있다.

 

반대로 반공변의 코드를 보자.

List<? super Integer> intInt = new ArrayList<Integer>();  // Integer is a "superclass" of Integer (in this context)
List<? super Integer> intNum = new ArrayList<Number>();   // Number is a superclass of Integer
List<? super Integer> intObj = new ArrayList<Object>();   // Object is a superclass of Integer

 

결론적으로, 공변과 반공변을 통해서 다른 타입에 제한적인 작업이 가능하게 된다.

Comments