[Java] 제네릭 - 2

2024. 2. 19. 15:29Memorizing/Java

728x90

본 포스팅에서는 제네릭에서 유연성 캐스팅에 유연성을 더해주는 와일드카드에 대해 다룹니다.

정의

와일드카드는 아래와 같이 타입 변수를 지정할 때, 상속 관계를 어떤 방식으로 지정할지에 대해 "?"를 사용하여 지정하는 것을 말합니다.

1. <? extends T> : T와 그 자손들만 사용 가능
2. <? super T> : T와 그 조상들만 가능
3. <?> : 제한 없음

와일드카드 도입 이유

기본적으로 자바의 타입(기본형 타입, 참조형 타입)은 다운, 업 캐스팅을 지원합니다. 예제코드는 아래와 같습니다.

// 업캐스팅(공변성)
Object[] Covariance = new Integer[10];

// 다운캐스팅(반공변성)
Integer[] Contravariance = (Integer[]) Covariance;

하지만 제네릭은 아래와 같은 상황에서 다운,업 캐스팅을 지원하지 않습니다.

public static void print(List<Object> arr) {
    for (Object e : arr) {
        System.out.println(e);
    }
}

public static void main(String[] args) {
    List<Integer> integers = Arrays.asList(1, 2, 3);
    print(integers); // ! Error
}

따라서 아래와 같이 메소드 오버로딩을 작성해주어야합니다. 하지만, 이는 매우 비효율적입니다.

public static void print(List<Integer> arr) {
}

public static void print(List<Double> arr) {
}

public static void print(List<Number> arr) {
}

...

와일드카드의 상속

와일드 카드의 상속 중 "<? extends T> "케이스의 예제코드만 보도록 하겠습니다. 

아래와 같이 MyArrayList를 정의합니다. 아래와 같이 코드를 정의하면, Number의 하위 클래스를 모두 받을 수 있습니다. 따라서 Integer 참조형 변수를 타입으로 넣어도 업캐스팅이 잘 동작하는 것을 알 수 있습니다. 

class MyArrayList<T> {
    Object[] element = new Object[5];
    int index = 0;

    // 외부로부터 리스트를 받아와 매개변수의 모든 요소를 내부 배열에 추가하여 인스턴스화 하는 생성자
    public MyArrayList(Collection<? extends T> in) {
        for(T elem : in) {
            element[index++] = elem;
        }
    }
    
    // ...
}
public static void main(String[] args) {
    // MyArrayList의 제네릭 T 타입은 Number
    MyArrayList<Number> list;

    // MyArrayList 생성하기
    Collection<Integer> col = Arrays.asList(1, 2, 3, 4, 5);
    list = new MyArrayList<>(col);
    
    // MyArrayList 출력
    System.out.println(list); // [1, 2, 3, 4, 5]
}

'Memorizing > Java' 카테고리의 다른 글

[QueryDSL] 최신! 환경설정  (3) 2024.03.06
[Java] 초간단! 쿠키, 세션, 토큰  (0) 2024.02.29
[Java] 제네릭 - 1  (0) 2024.02.19
[Java] 프로세스와 스레드 - 4  (1) 2024.02.17
[Java] 프로세스와 스레드 - 3  (0) 2024.02.17