자바 와일드카드

2020. 4. 3. 11:11모바일/Android_Java

와일드카드

public static void printCollectionGen(Collection<Object> collection) {
    for (Object e : collection) {
        System.out.println(e);
    }
}

List<String> cities = new ArrayList<>();
cities.add("Changwon");
cities.add("Seoul");
cities.add("Suwon");
cities.add("Yongin");
printCollection(cities); // List<String>은 Collection의 서브타입이다.
// 결과:
// Changwon
// Seoul
// Suwon
// Yongin
printCollectionGen(cities); // List<String>은 Collection<Object>와 아무 관계가 없다.
// 컴파일 에러
  • printCollectionGen()이 제네릭도 사용하고 뭔가 있어 보이지만 이 메서드는 별로 쓸모가 없다. 앞서 말했듯이 자바 제네릭은 기본적으로 무변성이기 때문이다. Object가 최상위 클래스이긴 하지만 CollectionCollection, List과는 아무 관계가 없다

그렇다면 어떻게?

  • printCollectionGen()을 쓸모있게 만드려면 타입 파라미터에 Object 대신 와일드카드 ?를 사용해야 한다.
public static void printCollectionGen(Collection<?> collection) {
    for (Object e : collection) {
        System.out.println(e);
    }
}

바운드 와일드카드 타입(Bounded wildcard type)

바운드 와일드카드 타입에는 Upper bounded wildcard와 Lower bounded wildcard가 있다. Collection 계열 클래스들의 소스코드를 살펴보면 자주 볼 수 있는가 Upper bounded wildcard이고가 Lower bounded wildcard이다.

다른 말로 전자를공변(covariant)이라 하고 후자를반공변(contravariance)이라 부르는데 각각이 의미하는 내용은 다음과 같다.

무공변(invariant): 오로지 자기 타입만 허용하는 것

공변 (covariant): 구체적인 방향으로 타입 변환을 허용하는 것 (자기 자신과 자식 객체만 허용) <? extends T>

반공변 (contravariant): 추상적인 방향으로의 타입 변환을 허용하는 것(자기 자신과 부모 객체만 허용) <? super T>

앞에서 언급했듯이 매개변수화 타입은 무공변이라고 하였다. 왜 자기 타입만 허용하게 했을까? 만약 아래 코드가 허용된다고 가정해보자.

어차피 컴파일은 안되겠지만 된다고 가정했을 때 런타임에 에러를 발생시킨다. Java의 배열보다 나을 것이 없다는 것이다. 그래서 런타임에 안정성을 보장하기 위해 이런 방식을 택했는데 이는 몇 가지 영향을 준다.

위 코드를 보면 논리적으로 문제가 없어 보이지만Collection은Collection

의 서브타입이 아니기 때문에 컴파일에 실패한다. 위 코드가 컴파일 되려면addAll메소드의 시그니처를 다음과 같이 변경해야 한다.

위에서 몇 번 언급했던 내용이기에 중복되는 느낌이 없지 않지만 반복학습의 개념으로봐주시면 좋을 것 같다. extends-bound, super-bound는PECS라는 개념으로도 사용된다.

'모바일 > Android_Java' 카테고리의 다른 글

recyclerview onresume 화면재갱신 하지 않기!  (0) 2020.06.19
Fragment에서 getActivity().findViewById() = null  (0) 2020.05.22
FragmentActivity vs Activity  (0) 2020.04.03
정규 표현식  (0) 2020.02.07
스택,힙,GC  (0) 2020.01.30