티스토리 뷰

개발관련/java

PECS - java generic

xephysis 2021. 5. 8. 18:25

배경

  • generic 에서 사용되는 변성 관련 super, extends 사용처 정리

요약

  • generic 타입을 넣는다면, 소비(consume)하면 super
  • lower bound can write (super)
  • generic 타입을 꺼낸 다면, 생산(produce)하면 extends
  • upper bound can read (extends)

super - consume - 데이터를 넣음 - 공변

package me.xep.study;

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void addNumbersWithSuper(List<? super Integer> list) {
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
    }

    // 이런건 안된다는 거다. List<? extends Number> list 도 마찬가지다
    //    public static void addNumbersWithExtends(List<? extends Integer> list) {
    //        for (int i = 0; i < 10; i++) {
    //            list.add(Integer.valueOf(i));
    //        }
    //    }

    public static void main(String[] args) {
        List<Integer> integerList = new ArrayList<>();

        addNumbersWithSuper(integerList);
        System.out.println(integerList);

        List<Number> numberList = new ArrayList<>();
        addNumbersWithSuper(numberList);
        System.out.println(numberList);
    }
}

extends - produce - 데이터를 꺼냄 - 반공변

package me.xep.study;

import java.util.List;

public class Test {

    public static double sumNumbersWithExtends(List<? extends Number> list) {
        double total = 0.0;
        for (Number o : list) {
            total += o.doubleValue();
        }

        return total;
    }

    // for (Number o : list) { 여기서부터 문제가 발생한다. o의 타입은 Number 가 아닐수도 있다.
    //    public static double sumNumbersWithSuper(List<? super Number> list) {
    //        double total = 0.0;
    //        for (Number o : list) {
    //            total += o.doubleValue();
    //        }
    //
    //        return total;
    //    }

    public static void main(String[] args) {
        List<Integer> integerList = List.of(1,2,3,4,5);
        System.out.println(sumNumbersWithExtends(integerList));

        List<Double> doubleList = List.of(1.1,1.2,1.3,1.4,1.5);
        System.out.println(sumNumbersWithExtends(doubleList));
    }
}

재미있는 글을 찾아서 조금 더 정리

package me.xep.study;

import java.sql.Array;
import java.util.ArrayList;
import java.util.List;

class A {};
class B extends A {}
class C extends B {};

public class Test {
    public static void main(String[] args) {
        List<? super B> listOfSuperB = new ArrayList<>();
        // consume / super -> 이래서 pe'cs'
        //listOfSuperB.add(new A()); //안됨
        listOfSuperB.add(new B()); //됨
        listOfSuperB.add(new C()); //됨

        B b = new C(); //되는 이유
        listOfSuperB.add(b);
        //B b = new A(); //안되는 이유
        //listOfSuperB.add(b);

        // produce / super
        for (Object o : listOfSuperB) {
            // o의 타입을 확정 지을수가 없다
            // ? extends B 라면 명시적으로 B로 캐스팅해서 쓸 수 있지만 super 라면 불가능
        }

        List<? extends B> listOfExtendsB = new ArrayList<>();
        // consume / extends -> 다 안됨 -> 아에 넣는 행위 자체를 금지한다
        // '꺼내는 시점에서는' 뭐가 들어가 있을지 모르니까
        //listOfExtendsB.add(new A()); //안됨 ???
        //listOfExtendsB.add(new B()); //안됨 ?
        //listOfExtendsB.add(new C()); //안됨 ?

        // produce / extends -> 이래서 'pe'cs
        for (Object o : listOfExtendsB) {
            //for (B o : listOfExtendsB) { 도 가능, 결국 B의 자손들이니 B로 쓸 수 있다.

            B elem = (B) o;
        }

        // 그냥 궁금해서
        List<? extends B> listOfExtendsB2 = null;
        List<B> listOfB = new ArrayList<>();
        listOfExtendsB2 = listOfB; //직접 넣는것만 안되지 이건 잘 됨
        List<C> listOfC = new ArrayList<>();
        listOfExtendsB2 = listOfC; //직접 넣는것만 안되지 이건 잘 됨
    }
}

출처

'개발관련 > java' 카테고리의 다른 글

java 버전 별 인터페이스 메소드  (0) 2021.05.05
JVM Compressed OOPS  (0) 2021.03.29
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함