공공부하자개발 · 영어 학습 노트
자바
고급모던 자바와 성능0/10 완료
  • 01제네릭과 와일드카드
  • 02멀티스레드와 동기화
  • 03람다식과 함수형 인터페이스
  • 04Stream API와 병렬 처리
  • 05Optional로 NPE 방지
  • 06메서드 활용 패턴 (고급)
  • 07Java 21 모던 문법
  • 08어노테이션·리플렉션·동적 프록시
  • 09CompletableFuture 심화와 가상 스레드 실전
  • 10JVM 메모리·GC·OOM 진단
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 고급 › 01 / 10

제네릭과 와일드카드

섹션 7진행 0 / 10
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

6. 연습 문제

문제 1

Pair<A, B> 레코드를 만들고, 두 요소를 바꾼 Pair<B, A> 를 반환하는 swap() 메서드와, 첫 번째 요소를 변환하는 <C> Pair<C, B> mapFirst(Function<? super A, ? extends C> f) 메서드를 작성하세요. Pair.of("won", 1000) 으로 만들어 두 메서드를 호출한 결과를 출력하세요.

정답 보기
java
import java.util.function.Function;

public class Ex1 {
    record Pair<A, B>(A first, B second) {
        static <A, B> Pair<A, B> of(A a, B b) { return new Pair<>(a, b); }
        Pair<B, A> swap() { return new Pair<>(second, first); }
        <C> Pair<C, B> mapFirst(Function<? super A, ? extends C> f) {
            return new Pair<>(f.apply(first), second);
        }
    }

    public static void main(String[] args) {
        Pair<String, Integer> p = Pair.of("won", 1000);
        System.out.println(p.swap());                     // Pair[first=1000, second=won]
        System.out.println(p.mapFirst(String::length));   // Pair[first=3, second=1000]
    }
}
// 출력:
// Pair[first=1000, second=won]
// Pair[first=3, second=1000]

문제 2

List<? extends Number> 두 개를 받아 각 인덱스의 합을 List<Double> 로 돌려주는 static List<Double> zipSum(List<? extends Number> a, List<? extends Number> b) 를 작성하세요. 길이가 다르면 짧은 쪽 기준입니다.

zipSum(List.of(1, 2, 3), List.of(0.5, 0.5)) 의 결과를 출력하세요. 그리고 왜 파라미터를 List<Number> 로 선언하면 List.of(1, 2, 3) 을 넘길 수 없는지 주석으로 설명하세요.

정답 보기
java
import java.util.*;

public class Ex2 {
    // List<Number> 로 선언하면 List<Integer> 는 불공변 때문에 대입 불가.
    // 읽기만 하므로 PECS 의 producer → ? extends Number.
    static List<Double> zipSum(List<? extends Number> a, List<? extends Number> b) {
        int n = Math.min(a.size(), b.size());
        List<Double> out = new ArrayList<>(n);
        for (int i = 0; i < n; i++) out.add(a.get(i).doubleValue() + b.get(i).doubleValue());
        return out;
    }

    public static void main(String[] args) {
        System.out.println(zipSum(List.of(1, 2, 3), List.of(0.5, 0.5)));
    }
}
// 출력:
// [1.5, 2.5]

문제 3

sealed interface Shape permits Circle, Rect 와 두 record 를 정의하고, <T extends Shape> T largest(List<T> shapes) 를 작성하세요. 넓이는 Shape 에 double area() 추상 메서드를 두고 각 record 가 구현합니다.

largest(List.of(new Circle(1), new Circle(2))) 의 반환 타입이 Circle 로 추론되어 radius() 를 바로 호출할 수 있음을 보이세요.

정답 보기
java
import java.util.*;

public class Ex3 {
    sealed interface Shape permits Circle, Rect { double area(); }
    record Circle(double radius) implements Shape { public double area() { return Math.PI * radius * radius; } }
    record Rect(double w, double h) implements Shape { public double area() { return w * h; } }

    // 반환 타입이 T 이므로 List<Circle> 을 넘기면 Circle 이 돌아온다 (Shape 로 넓어지지 않음)
    static <T extends Shape> T largest(List<T> shapes) {
        T best = shapes.get(0);
        for (T s : shapes) if (s.area() > best.area()) best = s;
        return best;
    }

    public static void main(String[] args) {
        Circle c = largest(List.of(new Circle(1), new Circle(2)));
        System.out.println("radius = " + c.radius());
        Shape any = largest(List.of(new Circle(1), new Rect(3, 3)));   // T = Shape
        System.out.println(any);
    }
}
// 출력:
// radius = 2.0
// Rect[w=3.0, h=3.0]
연습 문제
  • 문제 1
  • 문제 2
  • 문제 3
이전 섹션5 자주 하는 실수 (Tip)6 / 7다음 섹션7 정리