제네릭(Generics) 계념

2024. 6. 25. 21:03Java/기초

제네릭(Generics) 

  • 자바에서 타입을 매개변수로 사용할 수 있게 하는 기능으로, 코드의 재사용성을 높이고, 타입 안정성을 보장하며, 컴파일 시 타입 체크를 강화할 수 있습니다.
  • 제네릭을 사용하면 클래스나 메서드를 정의할 때 구체적인 데이터 타입을 지정하지 않고, 사용할 때 타입을 지정할 수 있습니다. 이는 코드의 가독성을 높이고, 타입 캐스팅과 관련된 오류를 줄이는 데 도움을 줍니다.

제네릭 클래스

public class Box<T> {
    private T content;

    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }
}

// 사용 예
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String content = stringBox.getContent();
System.out.println(content);  // 출력: Hello
  • 여기서 T는 타입 매개변수입니다. Box 클래스는 T 타입의 객체를 담을 수 있으며, 실제 사용 시에는 T가 구체적인 타입(예: String)으로 대체됩니다.

 


제네릭 메서드

public class Util {
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }
}

// 사용 예
Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"A", "B", "C"};

Util.printArray(intArray);   // 출력: 1 2 3 4 5
Util.printArray(stringArray); // 출력: A B C
  • 메서드 선언 시 <T>를 사용하여 타입 매개변수를 지정하고, 메서드 본문에서 T를 사용할 수 있습니다.

 


제네릭 타입 제한 (Bounded Type Parameters)

public class NumberBox<T extends Number> {
    private T number;

    public void setNumber(T number) {
        this.number = number;
    }

    public T getNumber() {
        return number;
    }

    public double doubleValue() {
        return number.doubleValue();
    }
}

// 사용 예
NumberBox<Integer> integerBox = new NumberBox<>();
integerBox.setNumber(10);
System.out.println(integerBox.doubleValue()); // 출력: 10.0

NumberBox<Double> doubleBox = new NumberBox<>();
doubleBox.setNumber(3.14);
System.out.println(doubleBox.doubleValue()); // 출력: 3.14
  • 여기서 T extends Number는 T가 Number 클래스의 서브클래스여야 함을 나타냅니다.

  • 자주 사용하는 타입인자
  • <E> : Element
  • <N> : Number
  • <R> : Result
  • <V> : Value
  • <K> : Key
  • <T> : Type

와일드카드 (Wildcards)

  • 제네릭에서는 ?를 사용하여 와일드카드를 표현할 수 있습니다. 와일드카드는 제네릭 타입의 유연성을 높이기 위해 사용됩니다. 와일드카드는 다음과 같이 세 가지 형태로 사용할 수 있습니다:
  1. 제한 없는 와일드카드: <?>
  2. 상한 경계 와일드카드: <? extends Type>
  3. 하한 경계 와일드카드: <? super Type>
public static void printList(List<?> list) {
    for (Object elem : list) {
        System.out.println(elem);
    }
}

public static void main(String[] args) {
    List<Integer> intList = Arrays.asList(1, 2, 3);
    List<String> strList = Arrays.asList("one", "two", "three");

    printList(intList);  // 출력: 1 2 3
    printList(strList);  // 출력: one two three
}
  • 와일드카드를 사용하면 다양한 타입의 리스트를 하나의 메서드로 처리할 수 있습니다.
  • 제네릭을 사용하면 코드의 재사용성을 높이고, 타입 안정성을 보장하며, 컴파일 시 타입 체크를 강화할 수 있어, 보다 안전하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.