WEB개발/JAVA

제너릭 Generic

wooyeon06 2024. 12. 18. 15:31
Java의 제너릭(Generic) 타입은 클래스나 메서드에서 사용할 데이터 타입을 컴파일 시에 지정할 수 있도록 하는 기능입니다. 제너릭은 타입 안정성을 제공하고, 캐스팅 작업을 줄여 코드를 더 간결하고 안전하게 만듭니다.

 

1. 제너릭 클래스

class Box<T> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

public class GenericClassExample {
    public static void main(String[] args) {
        // Integer 타입의 Box
        Box<Integer> intBox = new Box<>();
        intBox.setValue(123);
        System.out.println("Integer Box: " + intBox.getValue());

        // String 타입의 Box
        Box<String> strBox = new Box<>();
        strBox.setValue("Hello");
        System.out.println("String Box: " + strBox.getValue());
    }
}

 

** Java의 제네릭 클래스는 객체가 생성될 때 타입이 결정됩니다. 제네릭 클래스의 타입 파라미터는 객체를 인스턴스화할 때 전달되며, 컴파일 타임에 타입이 고정됩니다.

 

 

2. 제너릭 메소드

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

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3};
        String[] strArray = {"A", "B", "C"};

        printArray(intArray); // 출력: 1 2 3
        printArray(strArray); // 출력: A B C
    }
}

 

** 제네릭 메서드의 타입 결정 시점

  1. 타입 추론: 컴파일러가 메서드를 호출하는 문맥에서 전달된 인자를 보고 타입을 자동으로 추론합니다.
  2. 명시적 타입 지정: 호출 시 타입을 명시할 수도 있으며, 이 경우 타입 추론 대신 명시된 타입을 사용합니다.
public class GenericMethodExample {
    public static <T> void print(T item) {
        System.out.println(item);
    }

    public static void main(String[] args) {
        print("Hello"); // 컴파일러가 T를 String으로 추론
        print(123);     // 컴파일러가 T를 Integer로 추론
    }
}

 

public class GenericMethodExample {
    public static <T> void print(T item) {
        System.out.println(item);
    }

    public static void main(String[] args) {
        GenericMethodExample.<String>print("Hello"); // T를 String으로 명시
    }
}

 

 

3. 제너릭 타입 제한 (Bounded Type Parameters)

class NumberBox<T extends Number> {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public double getDoubleValue() {
        return value.doubleValue();
    }
}

public class BoundedTypeExample {
    public static void main(String[] args) {
        NumberBox<Integer> intBox = new NumberBox<>();
        intBox.setValue(123);
        System.out.println("Double Value: " + intBox.getDoubleValue()); // 출력: 123.0

        NumberBox<Double> doubleBox = new NumberBox<>();
        doubleBox.setValue(45.67);
        System.out.println("Double Value: " + doubleBox.getDoubleValue()); // 출력: 45.67
    }
}

 

 

4. 와일드카드 (Wildcard)

와일드카드는 제너릭 타입을 보다 유연하게 사용하도록 도와줍니다.

 

<?> 임의의 타입 (모든 타입 가능)
<? extends 상위클래스>  상위 클래스 또는 그 하위 타입만 허용
<? super 하위클래스> 하위 클래스 또는 그 상위 타입만 허용

 

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

public class WildcardExample {
    // 상한 제한
    public static void printNumbers(List<? extends Number> list) {
        for (Number number : list) {
            System.out.println(number);
        }
    }

    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        intList.add(1);
        intList.add(2);

        List<Double> doubleList = new ArrayList<>();
        doubleList.add(1.1);
        doubleList.add(2.2);

        printNumbers(intList);   // 출력: 1 2
        printNumbers(doubleList); // 출력: 1.1 2.2
    }
}