상한 와일드카드
생산자를 위한 ? extends T를 알아봅니다
상한 와일드카드은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
제네릭은 불변입니다
Java에서 제네릭은 불변입니다. Integer가 Number이더라도 List<Integer>는 List<Number>가 아닙니다.
처음 접하는 사람에게는 놀라울 수 있지만, 이는 타입 시스템의 건전성을 유지합니다. 와일드카드는 이 제한을 안전하게 완화합니다.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> ints = List.of(1, 2, 3);
// List<Number> nums = ints; // would NOT compile
System.out.println("List<Integer> is not List<Number>");
System.out.println(ints);
}
}상한이 있는 와일드카드
? extends T는 상한이 있는 와일드카드입니다. 이는 "T 또는 T의 하위 타입인 어떤 알려지지 않은 타입"을 의미합니다.
List<? extends Number>는 List<Integer>, List<Double> 또는 List<Number>를 가리킬 수 있습니다.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? extends Number> a = List.of(1, 2, 3);
List<? extends Number> b = List.of(1.5, 2.5);
System.out.println(a.get(0));
System.out.println(b.get(0));
}
}생산자에서 읽기
? extends Number를 사용하면 요소를 Number로 안전하게 읽을 수 있습니다.
실제 요소 타입이 무엇이든 숫자 타입이거나 그 하위 타입임이 보장되므로 읽기가 타입 안전합니다.
import java.util.List;
public class Main {
static double sum(List<? extends Number> list) {
double total = 0;
for (Number n : list) total += n.doubleValue();
return total;
}
public static void main(String[] args) {
System.out.println(sum(List.of(1, 2, 3)));
System.out.println(sum(List.of(1.5, 2.5)));
}
}여기에는 쓸 수 없습니다
여기서 중요한 점은 ? extends Number 리스트에는 요소를 추가할 수 없다는 것입니다(null은 예외입니다).
컴파일러는 정확한 요소 형식을 알 수 없습니다. 실제로는 List<Integer>일 수 있으므로 Double을 추가하면 안전하지 않습니다.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? extends Number> list = new ArrayList<Integer>();
// list.add(1); // does NOT compile
// list.add(1.5); // does NOT compile
System.out.println("Cannot add to ? extends Number");
System.out.println("size = " + list.size());
}
}쓰기가 금지되는 이유
쓰기가 허용된다고 가정해 보겠습니다. List<Integer>를 List<? extends Number>로 전달한 다음 Double을 추가할 수 있을 것입니다.
나중에 리스트를 List<Integer>로 읽는 코드에서 ClassCastException이 발생합니다. 컴파일러는 쓰기를 금지하여 이를 방지합니다.
import java.util.List;
public class Main {
public static void main(String[] args) {
// Conceptual: this is why add is blocked
System.out.println("Writing a Double into a List<Integer> would corrupt it");
System.out.println("so ? extends bans all adds");
}
}생산자 사용 사례
메서드가 값을 사용자에게 전달하기만 할 때(값을 읽어 올 때) ? extends T를 사용합니다.
원본 컬렉션에서 요소를 복사해 오는 메서드가 대표적인 예입니다.
import java.util.ArrayList;
import java.util.List;
public class Main {
static List<Number> copyOut(List<? extends Number> source) {
List<Number> dest = new ArrayList<>();
for (Number n : source) dest.add(n);
return dest;
}
public static void main(String[] args) {
System.out.println(copyOut(List.of(1, 2, 3)));
}
}제한된 형식 매개변수와 와일드카드
<T extends Number>(제한된 형식 매개변수)와 ? extends Number(와일드카드)를 혼동하지 마십시오.
- 형식 매개변수: 메서드 전체에서 사용할 형식에 이름을 붙입니다.
- 와일드카드: 이름을 붙일 필요가 없을 때 사용하는, 이름이 없는 미지의 하위 형식입니다.
import java.util.List;
public class Main {
static <T extends Number> T first(List<T> list) { return list.get(0); }
public static void main(String[] args) {
Integer i = first(List.of(10, 20));
System.out.println(i);
}
}다중 제한
형식 매개변수에는 &를 사용해 여러 제한을 지정할 수 있습니다. 예를 들어 <T extends Number & Comparable<T>>와 같이 작성합니다.
와일드카드는 상한을 하나만 지원하므로 여러 제한이 필요하면 이름이 있는 형식 매개변수를 사용해야 합니다.
import java.util.List;
public class Main {
static <T extends Number & Comparable<T>> T max(List<T> list) {
T best = list.get(0);
for (T t : list) if (t.compareTo(best) > 0) best = t;
return best;
}
public static void main(String[] args) {
System.out.println(max(List.of(3, 9, 1, 7)));
}
}Collections.max와 와일드카드
JDK는 상한을 폭넓게 사용합니다. 예를 들어 읽기 전용 컬렉션의 합을 계산하거나 내용을 살펴볼 때 활용합니다.
여기서는 생산자로 지정된 리스트에서 가장 큰 값을 찾습니다.
import java.util.List;
public class Main {
static double largest(List<? extends Number> nums) {
double max = Double.NEGATIVE_INFINITY;
for (Number n : nums) max = Math.max(max, n.doubleValue());
return max;
}
public static void main(String[] args) {
System.out.println(largest(List.of(4, 2, 9, 1)));
System.out.println(largest(List.of(0.5, 9.9, 3.3)));
}
}쓸 수 있는 값은 null뿐입니다
? extends T 컬렉션에 추가할 수 있는 유일한 값은 null입니다. null은 모든 참조 형식에 할당할 수 있기 때문입니다.
실제로 유용한 경우는 드물지만, add가 완전히 금지된 것이 아니라 사실상 사용할 수 없는 이유를 설명해 줍니다.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? extends Number> list = new ArrayList<Number>();
// Only null is assignable; demonstrated conceptually
System.out.println("Only null could be added; we avoid that");
System.out.println("size = " + list.size());
}
}항상 Object로 읽어 올 수 있습니다
모든 형식은 Object를 상속하므로 어떤 와일드카드 리스트의 요소든 항상 Object로 읽을 수 있습니다.
상한이 Number라면 요소를 Number로 바로 읽을 수 있다는 이점도 있습니다.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? extends Number> nums = List.of(1, 2.0, 3L);
for (Object o : nums) System.out.println(o.getClass().getSimpleName());
}
}빠른 확인
상한에 대한 이해도를 확인해 보십시오.
복습
상한이 있는 와일드카드를 배웠습니다.
? extends T는 T의 이름을 알 수 없는 하위 형식을 의미합니다.- 요소를 T로 읽을 수 있습니다(생산자).
- null이 아닌 요소는 추가할 수 없습니다.
- 제네릭은 불변이며, 와일드카드는 이를 안전하게 완화합니다.
다음에는 이와 반대되는 개념인 하한이 있는 와일드카드를 살펴봅니다.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? extends Number> nums = List.of(1, 2, 3);
System.out.println("Upper bound recap: read " + nums.get(0));
}
}자주 묻는 질문
“상한 와일드카드” 강의는 무료인가요?
네 — “상한 와일드카드” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“상한 와일드카드”에서 뭘 배우나요?
생산자를 위한 ? extends T를 알아봅니다 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Java Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“상한 와일드카드” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 상한 와일드카드
- 하한 와일드카드
- PECS 원칙
- API에서 와일드카드 사용