Covariant, Contravariant, Invariant 정의

Covariant / Contravariant / Invariant 정의

Covariant : sub-type을 super-type으로 교체 가능한 성질.
Contravariant : super-type을 sub-type으로 교체 가능한 성질.
Invariant : 위 둘 모두가 허용되지 안는 성질.

Java Array는 Covariant 하다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class CovariantTest {
    public static void main(String[] args) {
        Integer[] integers = new Integer[10];
        for (int i = 0; i < integers.length; i++) {
            integers[i] = i;
        }

        // covariant: A feature which allows to substitute a subtype with supertype.
        // array is covariant.
        Number[] numbers = integers;
        for (int i = 0; i < numbers.length; i++) {
            System.out.println(numbers[i]);
        }
    }
}

Java Generic은 Invariant 하다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class InvariantTest {
    public static void main(String[] args) {
        List<Integer> integerList = new ArrayList<>();
        integerList.add(0);
        integerList.add(1);
        integerList.add(2);

        // invariant: A feature does not allow any of substitutions.
        // generic is invariant.
        List<Number> numberList = integerList; // compile error.
    }
}

Wildcard Extend Generic은 Covariant 하다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class InvariantTest {
    public static void main(String[] args) {
        List<Integer> integerList = new ArrayList<>();
        integerList.add(0);
        integerList.add(1);
        integerList.add(2);

        // wildcard extend generic is covariant.
        List<? extends Number> numberList = integerList;
//        numberList.add(10); // compile error.

        for (Number n : numberList) {
            System.out.println(n);
        }
    }
}
10 line의 compile error 원인>
'? extend Number'는 Number를 extend 했다는 의미이며 컴파일러는 어떤 타입인지는 알수 없으므로 null 혹은 element 삭제만 가능하고 추가는 불가능 하다.

Wildcard Super Generic은 Contravariant 하다.

 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
class ContravariantTest {
    public static void main(String[] args) {
        List<A> aList = new ArrayList<>();
        aList.add(new A());

        // contravariant: A feature which allows to substitute supertype with subtype.
        // wildcard super generic is contravariant.
        List<? super B> bList = aList;
        bList.add(new B());
//        bList.add(new A()); // compile error.

        for (int i = 0; i < bList.size(); i++) {
            System.out.println(bList.get(i));
        }
    }

    private static class A {
        @Override
        public String toString() {
            return "A";
        }
    }

    private static class B extends A {
        @Override
        public String toString() {
            return "B";
        }
    }
}
9 line의 element 추가가 가능한 이유>
'? super B'는 B의 super-type이 확실하다는 의미임으로 B는 자신의 super-type에 대입이 가능 하기 때문이다. 그러나, 컴파일러는 B의 어떤 super-type인지는 알수가 없으므로 10 line처럼 A element나 A의 다른 sub-type은 추가할 수 없다.

참고: https://www.logicbig.com/tutorials/core-java-tutorial/java-language/java-subtyping-rules.html

댓글

이 블로그의 인기 게시물

[Protocol] WIEGAND 통신

Orange for Oracle에서 한글 깨짐 해결책

[UI] GNB·LNB·SNB·FNB 용어 설명