JAVA

Generic

neal89 2025. 3. 7. 06:08

📌 제네릭(Generic)이란?

  • 자바에서 타입을 일반화하여 코드 재사용성과 타입 안정성을 높이는 기능
  • 클래스, 인터페이스, 메서드에서 사용할 수 있음

1️⃣ 제네릭이 필요한 이유

💡 기존 방식의 문제점

  • IntegerBox, StringBox 같은 클래스를 각각 만들어야 함 → 코드 중복 발생
  • Object를 활용한 다형성으로 해결 가능하지만, 타입 안정성이 떨어짐
    • 잘못된 타입의 값이 들어가도 컴파일 오류 없이 실행됨
    • 다운 캐스팅이 필요하여 런타임 예외 발생 위험 증가

2️⃣ 제네릭 클래스 적용

public class GenericBox<T> {
    private T value;
    public void set(T value) { this.value = value; }
    public T get() { return value; }
}
  • T는 타입 매개변수로, 실제 사용하는 시점에 타입이 결정됨
  • 객체 생성 시 원하는 타입 지정
    GenericBox<Integer> integerBox = new GenericBox<>();
    integerBox.set(10);
    Integer value = integerBox.get(); // ✅ 타입 캐스팅 불필요
    
  • 코드 재사용성과 타입 안전성 동시 해결

3️⃣ 타입 매개변수 제한 (extends)

public class AnimalHospital<T extends Animal> { // Animal과 그 자식만 허용
    private T animal;
    public void set(T animal) { this.animal = animal; }
    public T get() { return animal; }
}
  • <T extends Animal>: T는 Animal 또는 그 하위 클래스만 가능
  • 타입 안정성을 보장하며, Animal의 기능 (getName(), getSize()) 사용 가능

4️⃣ 제네릭 메서드 (<T>)

public class Utility {
    public static <T> T identity(T value) { return value; }
}
  • 메서드 단위에서 제네릭을 적용하여 입력과 출력 타입을 동적으로 지정 가능
  • 호출 시 타입 명시 가능 (Utility.<Integer>identity(10)), 하지만 타입 추론 자동 적용

5️⃣ 와일드카드 (?)

🔹 ? extends T (상한 제한)

public static void processAnimals(List<? extends Animal> list) {
    for (Animal a : list) { System.out.println(a.getName()); }
}
  • Animal과 그 하위 클래스 리스트만 허용 (읽기 가능, 쓰기 불가)

🔹 ? super T (하한 제한)

public static void addAnimals(List<? super Dog> list) {
    list.add(new Dog("멍멍이", 100)); // ✅ Dog 또는 그 부모 타입 리스트에 추가 가능
}
  • Dog와 그 상위 클래스 리스트만 허용 (쓰기 가능, 읽기는 Object 타입)

6️⃣ 타입 이레이저 (Type Erasure)

  • 컴파일 시 제네릭 타입이 제거되고 Object로 변환됨
  • 따라서 기본형 타입 (int, double) 직접 사용 불가래퍼 클래스 (Integer, Double) 사용해야 함

📌 정리

구분 특징 장점

제네릭 클래스 <T>를 사용해 클래스 레벨에서 타입 결정 코드 재사용성 증가
제네릭 메서드 <T>를 사용해 메서드 단위에서 타입 결정 유연한 타입 적용 가능
와일드카드 (?) 제네릭 타입을 더 유연하게 활용 가능 타입 제한 (extends, super) 가능

🚀 제네릭을 활용하면 타입 안정성을 유지하면서도 유연한 코드를 작성할 수 있음! 🎯