자바의 공변성 (Convariance), 반공변성 (Contravariance), 불변성 (Invariance)

CJI0524·2025년 1월 25일
0

Java/Class

목록 보기
8/8

1. 공변성 (Convariance)

1.1. 공변성의 정의

공변성이란 타입 간 계층관계(상속)가 같은 방향으로 적용되는 것을 의미한다.

예를 들어 S 가 T 의 하위 타입이면,

S[]T[] 의 하위 타입이다.
List<S>List<T> 의 하위 타입이다.

이러한 공변성은 타입 간의 상속 관계를 복합 타입에서도 유지할 수 있게 해준다. 이를 통해 더 유연하고 재사용 가능한 코드를 작성할 수 있다.


1.2. 공변성의 예시

[1] 배열의 공변성

자바의 배열은 공변성을 지원한다. 즉, StringObject의 서브타입이라면, String[]Object[]의 서브타입이 된다.

✍️ 작성


public class ex1 {

    public static void main(String[] args) {
        String[] stringArray = {"Hello", "World"};
		Object[] objectArray = stringArray; // 가능: String[]은 Object[]의 서브타입

		objectArray[0] = "Hi";
		objectArray[1] = 42; // 런타임 오류: ArrayStoreException 발생
    }
}

String[]Object[]의 서브타입이므로, String[]Object[]타입으로 참조할 수 있음을 확인할 수 있다.
그러나 objectArray를 통해 Integer를 추가하려고 하면, 실제 배열은 String[]이므로 ArrayStoreException이 발생한다.

이는 공변성의 단점으로, 배열이 타입 안전성을 보장하지 못한다.

[2] 지네릭의 공변성

지네릭에서는 공변성을 지원하지 않지만, 와일드카드(?)를 사용하여 간접적으로 공변성을 구현할 수 있다. 와일드카드는 지네릭 타입의 불특정한 타입 매개변수를 표현한다.

✍️ 작성


public class ex1 {

    public static void main(String[] args) {
        List<? extends Number> numberList = new ArrayList<Integer>();
		Number num = numberList.get(0); // 가능 --> 실제로는 numberList가 비어있어 컴파일 오류

    }
}

다음 코드에서 쓰인 공변적 와일드카드 (<? extends T>)T 타입과 그 서브타입들을 허용한다.



2. 반공변성 (Contravariance)

2.1. 반공변성의 정의

반공변성이란 타입 간 계층관계가 반대 방향으로 적용되는 것을 의미한다.

예를 들어 S 가 T 의 하위 타입이면,

T[]S[] 의 하위 타입이다. (공변성의 반대)
List<T>List<S> 의 하위 타입이다. (공변성의 반대)

2.2. 반공변성의 예시

지네릭에서는 반공변성을 지원하지 않지만, 와일드카드(?)를 사용하여 간접적으로 반공변성을 구현할 수 있다. 와일드카드는 지네릭 타입의 불특정한 타입 매개변수를 표현한다.

✍️ 작성

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

public class ContravarianceExample {
    public static void main(String[] args) {
        // List<? super Integer>은 Integer와 그 슈퍼타입(Object)을 허용
        List<? super Integer> superNumberList = new ArrayList<Object>();

        // 요소 추가가 가능
        superNumberList.add(10);      // Integer 추가
        superNumberList.add(20);      // Integer 추가
        // superNumberList.add("Hello"); // 컴파일 오류: String은 Integer의 슈퍼타입이 아님

        // 요소 읽기: Object 타입으로 반환
        Object obj1 = superNumberList.get(0);
        Object obj2 = superNumberList.get(1);

        System.out.println("첫 번째 요소: " + obj1);
        System.out.println("두 번째 요소: " + obj2);
    }
}

🖥️ 결과

첫 번째 요소: 10
두 번째 요소: 20

superNumberListInteger와 그 슈퍼타입인 Object를 포함할 수 있는 리스트를 참조한다.



3. 불변성 (Invariance)

3.1. 불변성의 정의

자바의 제네릭은 불변성(Invariance)을 기본으로 한다. 이는 제네릭 타입의 상속 관계가 타입 매개변수의 상속 관계에 영향을 받지 않는다는 것을 의미한다. 즉, List<String>List<Object>의 상위 타입도, 하위 타입도 아니다.

이러한 불변성은 타입 매개변수의 상속 관계 무시를 무시하며 타입 안전성을 보장하고 유연성을 제한한다.

3.2. 불변성의 예시

✍️ 작성

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

public class InvarianceExample {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.add("Hello");
        stringList.add("World");

        // List<Object> objectList = stringList; // 컴파일 오류: 불변성으로 인해 호환되지 않음

        // 해결 방법: 와일드카드 사용
        List<? extends Object> wildcardList = stringList; // 가능

        Object obj1 = wildcardList.get(0); // 가능
        Object obj2 = wildcardList.get(1); // 가능

        System.out.println("첫 번째 요소: " + obj1);
        System.out.println("두 번째 요소: " + obj2);

        // 요소 추가는 불가능
        // wildcardList.add("Java"); // 컴파일 오류
    }
}

🖥️ 결과

첫 번째 요소: Hello
두 번째 요소: World

List<String>List<Object>의 상위 타입도, 하위 타입도 아니므로 직접적으로 할당할 수 없다.

4.해당 게시글 작성에 참고한 글 목록

자바 제네릭 불공변 / 공변 / 반공변 처음 들어봅니다.
자바에서 공변성(covariance), 반공변성(contravariance) 그리고 무변성 (invariance)
Java 배열과 리스트의 공변성과 반공변성, 무공변성
☕ 자바 제네릭의 공변성 & 와일드카드 완벽 이해

profile
개발돌이

0개의 댓글