0Pricing
Java Academy · 강의

하한 와일드카드

소비자를 위한 ? super T를 알아봅니다

하한 와일드카드은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

하한이 있는 와일드카드

? super T는 하한이 있는 와일드카드입니다. 이는 “T이거나 T의 상위 형식인, 정체를 알 수 없는 어떤 형식”을 의미합니다.

List<? super Integer>는 List<Integer>, List<Number> 또는 List<Object>를 가리킬 수 있습니다.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> a = new ArrayList<Number>();
        List<? super Integer> b = new ArrayList<Object>();
        a.add(1);
        b.add(2);
        System.out.println(a + " " + b);
    }
}

소비자에게 쓰기

? super Integer를 사용하면 모든 Integer(또는 Integer의 하위 형식)를 안전하게 추가할 수 있습니다.

실제 리스트 형식이 무엇이든 적어도 Integer의 어떤 상위 형식에 해당하는 리스트이므로 Integer는 항상 들어갈 수 있습니다.

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

public class Main {
    static void addNumbers(List<? super Integer> dest) {
        for (int i = 1; i <= 3; i++) dest.add(i);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        addNumbers(nums);
        System.out.println(nums);
    }
}

읽으면 Object를 얻습니다

대신 ? super T 리스트에서 읽을 때 컴파일러가 아는 것은 요소가 T의 정체를 알 수 없는 어떤 상위 형식이라는 사실뿐입니다.

읽기에 안전한 유일한 형식은 Object입니다.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> list = new ArrayList<Number>();
        list.add(10);
        Object o = list.get(0); // only Object is guaranteed
        // Integer i = list.get(0); // would NOT compile
        System.out.println(o);
    }
}

읽기가 제한되는 이유

List<? super Integer>가 실제로는 문자열을 담은 List<Object>일 수 있습니다.

따라서 읽기 결과는 어떤 Object든 될 수 있습니다. 컴파일러는 Integer라고 보장할 수 없으므로 읽기 결과는 Object로만 제공합니다.

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

public class Main {
    public static void main(String[] args) {
        List<Object> raw = new ArrayList<>();
        raw.add("a string");
        List<? super Integer> view = raw; // legal: Object is a supertype of Integer
        view.add(5);
        System.out.println(view.get(0).getClass().getSimpleName());
    }
}

소비자 사용 사례

메서드가 값을 소비하기만 할 때(값을 쓸 때) ? super T를 사용합니다.

대상 컬렉션을 채우는 메서드가 전형적인 사례입니다.

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

public class Main {
    static void fill(List<? super String> dest, int count) {
        for (int i = 0; i < count; i++) dest.add("item" + i);
    }
    public static void main(String[] args) {
        List<Object> objs = new ArrayList<>();
        fill(objs, 3);
        System.out.println(objs);
    }
}

하위 형식도 추가할 수 있습니다

? super Number를 사용하면 모든 Number와 그 하위 형식을 추가할 수 있습니다. 예를 들면 정수형, 실수형, 긴 정수형이 있습니다.

하한은 리스트가 적어도 Number를 받아들인다는 것을 보장하므로 모든 하위 형식을 넣을 수 있습니다.

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

public class Main {
    public static void main(String[] args) {
        List<? super Number> list = new ArrayList<Object>();
        list.add(1);      // Integer
        list.add(2.5);    // Double
        list.add(3L);     // Long
        System.out.println(list);
    }
}

Collections.addAll 방식

JDK는 값을 받아들이는 대상에 하한을 사용합니다. 예를 들어 요소를 대상에 넣는 제네릭 메서드가 그렇습니다.

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

public class Main {
    @SafeVarargs
    static <T> void addAll(List<? super T> dest, T... items) {
        for (T item : items) dest.add(item);
    }
    public static void main(String[] args) {
        List<Object> sink = new ArrayList<>();
        addAll(sink, "a", "b", "c");
        System.out.println(sink);
    }
}

super를 사용하는 비교기

실제 사용 사례로 Comparator<? super T>를 사용하면 상위 형식을 대상으로 작성된 비교기도 정렬에 사용할 수 있습니다.

어떤 Object든 toString으로 비교하는 비교기는 문자열 리스트도 정렬할 수 있습니다.

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

public class Main {
    public static void main(String[] args) {
        Comparator<Object> byString = Comparator.comparing(Object::toString);
        List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
        names.sort(byString); // List<String>.sort accepts Comparator<? super String>
        System.out.println(names);
    }
}

super와 extends는 서로 반대입니다

두 와일드카드는 서로 반대입니다.

  • ? extends T: T로 읽을 수 있지만 쓸 수는 없습니다. 생산자입니다.
  • ? super T: T를 쓸 수 있지만 읽을 때는 Object로만 읽을 수 있습니다. 소비자입니다.

이 대칭이 바로 다음에 배울 PECS 규칙의 핵심입니다.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> consumer = new ArrayList<Number>();
        consumer.add(1);
        System.out.println("consumer can write: " + consumer);
    }
}

제한이 다른 형식 사이에서 복사하기

복사 메서드는 두 와일드카드를 한 번에 보여 줍니다. ? extends T에서 읽고 ? super T에 씁니다.

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

public class Main {
    static <T> void copy(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Integer> src = List.of(1, 2, 3);
        List<Number> dest = new ArrayList<>();
        copy(src, dest);
        System.out.println(dest);
    }
}

와일드카드를 사용하지 말아야 할 때

메서드가 T를 읽기도 하고 쓰기도 한다면 와일드카드를 사용하지 마십시오. 정확한 형식이나 이름이 있는 형식 매개변수를 사용하십시오.

와일드카드는 읽기 전용 또는 쓰기 전용인 경우를 위해 존재합니다.

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

public class Main {
    static <T> void swapFirstTwo(List<T> list) {
        T tmp = list.get(0);
        list.set(0, list.get(1));
        list.set(1, tmp);
    }
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("a", "b"));
        swapFirstTwo(list);
        System.out.println(list);
    }
}

빠른 확인

하한에 대한 이해도를 확인해 보십시오.

복습

하한이 있는 와일드카드를 배웠습니다.

  • ? super T는 T의 정체를 알 수 없는 상위 형식을 의미합니다.
  • T와 그 하위 형식을 쓸 수 있습니다(소비자).
  • 읽기 결과는 Object로만 반환됩니다.
  • ? extends T와 정확히 반대되는 역할을 합니다.

다음에는 둘을 연결하는 규칙인 PECS를 살펴봅니다.

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

public class Main {
    public static void main(String[] args) {
        List<? super Integer> list = new ArrayList<Number>();
        list.add(42);
        System.out.println("Lower bound recap: " + list);
    }
}

자주 묻는 질문

“하한 와일드카드” 강의는 무료인가요?

네 — “하한 와일드카드” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“하한 와일드카드”에서 뭘 배우나요?

소비자를 위한 ? super T를 알아봅니다 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Java Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“하한 와일드카드” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 상한 와일드카드
  2. 하한 와일드카드
  3. PECS 원칙
  4. API에서 와일드카드 사용
← Java Academy(으)로 돌아가기