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
댓글
댓글 쓰기