Java Study

TIL- Java Generics

초코너무조코 2025. 1. 15. 11:56
728x90

 

목차


    제네릭스(Generics)란?

    제네릭스는 프로그래밍에서 데이터 타입에 의존하지 않고 다양한 타입을 처리할 수 있도록 하는 기능입니다. 이를 통해 코드의 재사용성을 높이고, 컴파일 시에 타입 오류를 미리 잡을 수 있어 안정성과 가독성도 향상됩니다. 특히 Java, C#, Kotlin 등에서 자주 사용되며, 현대 프로그래밍에서는 없어서는 안 될 중요한 개념입니다.


    왜 제네릭스를 사용해야 할까요?

    1. 타입 안전성 제네릭스를 사용하면 컴파일 타임에 타입 오류를 미리 방지할 수 있습니다. 타입 관련 오류를 런타임에서 찾는 것보다 훨씬 안전하게 코드를 작성할 수 있습니다.
    2. 코드 재사용성 제네릭을 활용하면 하나의 코드로 여러 타입을 처리할 수 있습니다. 예를 들어, Integer, String, Double 등 다양한 타입을 처리하는 클래스를 각각 구현할 필요가 없어집니다.
    3. 가독성 향상 제네릭스를 사용하면 코드에서 타입을 명확하게 지정할 수 있어, 다른 개발자가 코드를 읽고 이해하기 더 쉬워집니다.

    제네릭스 기본 예시 (Java)

    다음은 제네릭스를 활용한 간단한 예시입니다. Box라는 제네릭 클래스를 정의하고, 다양한 타입의 데이터를 저장할 수 있도록 합니다.

    // 제네릭 클래스 정의
    public class Box<T> {
        private T item;
        
        public void setItem(T item) {
            this.item = item;
        }
        
        public T getItem() {
            return item;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            // Integer 타입을 받는 Box 객체 생성
            Box<Integer> intBox = new Box<>();
            intBox.setItem(10);
            System.out.println("Item in intBox: " + intBox.getItem());
            
            // String 타입을 받는 Box 객체 생성
            Box<String> strBox = new Box<>();
            strBox.setItem("Hello, Generics!");
            System.out.println("Item in strBox: " + strBox.getItem());
        }
    }
    

    위 코드에서는 Box<T> 클래스가 T라는 타입 파라미터를 받아 다양한 타입을 처리할 수 있습니다. Integer와 String 타입으로 각각 Box 객체를 생성하고, 값을 저장하고 출력하는 예시입니다.


    제네릭 메소드 사용하기

    제네릭은 클래스 뿐만 아니라 메소드에서도 사용할 수 있습니다. 아래 예시는 제네릭 메소드 printArray를 통해, 어떤 타입의 배열이라도 출력할 수 있도록 만든 코드입니다.

    public class GenericMethodExample {
        public static <T> void printArray(T[] array) {
            for (T element : array) {
                System.out.print(element + " ");
            }
        }
    
        public static void main(String[] args) {
            Integer[] intArray = {1, 2, 3, 4};
            String[] strArray = {"Hello", "World"};
            
            printArray(intArray);  // Integer 타입 배열
            printArray(strArray);  // String 타입 배열
        }
    }
    

    <T>를 사용해 메소드가 어떤 타입의 배열이든 처리할 수 있도록 유연하게 만들었습니다.


    제네릭의 제한 (Bounded Type Parameters)

    타입 파라미터를 특정 클래스나 인터페이스로 제한할 수 있습니다. 예를 들어, Number 클래스나 그 하위 클래스만 사용할 수 있도록 제한할 수 있습니다.

    public class NumberBox<T extends Number> {
        private T value;
        
        public void setValue(T value) {
            this.value = value;
        }
        
        public T getValue() {
            return value;
        }
    }
    

    위 코드에서 T는 Number 클래스 또는 그 하위 클래스(Integer, Double, Float 등)만 받을 수 있습니다.


    와일드카드 사용하기 (Wildcard)

    제네릭스에서 와일드카드는 ?로 나타내며, 특정 타입을 유연하게 다룰 수 있습니다. 예를 들어, 모든 List 타입을 처리하고 싶다면 다음과 같이 사용할 수 있습니다.

    public static void printList(List<?> list) {
        for (Object obj : list) {
            System.out.println(obj);
        }
    }
    

    이렇게 하면 List<Integer>, List<String> 등 어떤 타입의 List도 처리할 수 있습니다.


    제네릭스를 사용할 때 주의사항

    1. 기본형 타입 사용 불가 Java에서는 기본형 타입(int, char, double)을 제네릭 타입으로 사용할 수 없습니다. 대신, Integer, Character, Double과 같은 래퍼 클래스를 사용해야 합니다.
    2. 타입 파라미터의 형변환 제네릭스는 타입을 명확히 지정하기 때문에 형변환을 자동으로 해주지 않습니다. 타입을 확실히 지정해줘야 합니다.
    3. 타입 소거(Type Erasure) 제네릭 타입은 컴파일 타임에만 존재하고, 런타임에는 타입이 사라집니다. 즉, 제네릭 타입에 대한 정보는 컴파일 후에는 사용할 수 없게 됩니다.

    마무리

    제네릭스는 타입 안전성, 코드 재사용성, 가독성 등을 제공하는 중요한 기능입니다. 이를 활용하면 코드가 더욱 깔끔하고 안정적이 되며, 다양한 타입을 유연하게 처리할 수 있습니다. 제네릭스를 잘 활용하면 프로그래밍에서 더 효율적이고 안전한 코드를 작성할 수 있습니다.

     

    728x90