Skip to content

공변성에 대한 이해 #25

@leejaeseung

Description

@leejaeseung

언어를 공부할 때마다 공변성에 관한 부분은 항상 나오지만, 쉽지 않은 개념이라 매번 확실히 이해하지 않고 넘겨왔던 것 같습니다.
이번에 팀 내부 스터디에서 공변성 관련 내용이 나왔는데 드디어 어느정도 이해를 한 것 같아 내용을 공유드리려 합니다.

저희 팀 테크 리더께서 공변성 관련 링크를 주셔서 대충이나마 번역해 보았습니다.
Difference between <? super T> and <? extends T> in Java [duplicate]

자바에서 <? super T> 와 <? extends T> 의 차이점

List<? extends T> 를 사용하면 list.add(e) 가 불가능하다. (요소 추가가 불가)

하지만 List<? super T> 에선 가능하다

extends

와일드카드 정의인 List<? extends Number> foo3 는 아래 모든 할당이 가능하다는 뜻이다.

List<? extends Number> foo3 = new ArrayList<Number>();  
// Number "extends" Number (in this context)

List<? extends Number> foo3 = new ArrayList<Integer>(); 
// Integer extends Number

List<? extends Number> foo3 = new ArrayList<Double>();  
// Double extends Number
  1. 읽기 - 위 할당에 따르면, List foo3 로부터 읽을 수 있는 객체 :
    • Number 를 읽을 수 있다. foo3 에 할당될 수 있는 목록에는 NumberNumber 의 하위 클래스가 포함되어 있기 때문이다.
    • Integer 는 읽을 수 없다. foo3List<Double> 타입일 수도 있기 때문이다.
    • Double 는 읽을 수 없다. foo3List<Integer> 타입일 수도 있기 때문이다.
  2. 쓰기 - 위 할당에 따르면, 위의 모든 List foo3 에 추가할 수 있는 객체 :
    • Integer 를 추가할 수 없다. foo3List<Double> 타입일 수도 있기 때문이다.
    • Double 를 추가할 수 없다. foo3List<Integer> 타입일 수도 있기 때문이다.
    • Number 를 추가할 수 없다. foo3List<Integer> 타입일 수도 있기 때문이다.

List 가 어떤 타입일 지 알 수 없으므로 List<? extends T> 에 어떤 객체도 추가할 수 없다. 타입을 보장받을 수 있는 건 읽을 때 T 혹은 T 의 서브 클래스라는 것 뿐이다.

super

이제 List <? super T> 를 보자.

와일드카드 정의인 List<? super Integer> foo3 는 아래 모든 할당이 가능하다는 뜻이다.

List<? super Integer> foo3 = new ArrayList<Integer>();
// Integer is a "superclass" of Integer (in this context)

List<? super Integer> foo3 = new ArrayList<Number>();   
// Number is a superclass of Integer

List<? super Integer> foo3 = new ArrayList<Object>();   
// Object is a superclass of Integer
  1. 읽기 - 위 할당에 따르면, List foo3 로부터 읽을 수 있는 객체 :
    • Integer 를 읽을 수 없다. foo3List<Number>List<Object> 타입일 수 있기 때문이다.
    • Number 를 읽을 수 없다. foo3List<Object> 타입일 수 있기 때문이다.
    • 오로지 보장받을 수 있는 건 ObjectObject 의 서브클래스일 거라는 것 뿐이다. (어떤 서브클래스인진 모르겠지만)
  2. 쓰기 - 위 할당에 따르면, 위의 모든 List foo3 에 추가할 수 있는 객체 :
    • Integer 를 추가할 수 있다. Integer 는 모든 list 들이 포함하고 있기 때문이다.
    • Integer 의 서브클래스도 마찬가지이다.
    • Double, Number, Object 는 추가할 수 없다. ArrayList<Integer> 타입일 수 있기 때문이다.

PECS

Remember PECS"Producer Extends, Consumer Super".

  • "Producer Extends" - T 값을 produce 하는 List 가 필요하다면(== T 값을 리스트로부터 읽고 싶다면) ? extends T 로 선언해야 한다. 하지만 이 리스트에 값을 추가할 순 없다.
  • "Consumer Super" - T 값을 consume 하는 List 가 필요하다면(== T 값을 리스트에 넣고 싶다면) ? super T 로 선언해야 한다. 하지만 이 리스트로부터 어떤 타입을 읽을지는 보장받을 수 없다.
  • 읽기와 쓰기를 모두 하고 싶다면, 정확한 타입을 정의해야 한다.

Extends vs Super 에 대해 이해한 내용

<? extends T>

  • ? 의 타입이 최대 T 타입인 걸 보장한다.
  • 읽기 가능
  • 공변
  • 코틀린의 out : 출력값이 T. 즉, out 하는 값이 최소 T 임이 보장.
  • 스칼라의 +

<? super T>

  • ? 의 타입이 최소 T 타입인 걸 보장한다.
  • 쓰기 가능
  • 반공변
  • 코틀린의 in : 입력값이 T. 즉, in 하는 값이 최대 T 임이 보장.
  • 스칼라의 -

공변성에 대해 저는 아래 그림처럼 이해하였습니다.

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions