본문 바로가기
Java

[Java] Generic

by goblin- 2024. 9. 28.

**제네릭(Generic)**은 자바의 기능으로, 클래스나 메서드에서 사용할 데이터 타입을 외부에서 지정할 수 있게 해줍니다. 즉, 제네릭을 사용하면 코드의 재사용성을 높이고, 컴파일 시점에 타입 안정성을 보장할 수 있습니다.

 

제네릭을 사용하면 다양한 데이터 타입을 처리할 수 있는 클래스를 정의하면서도, 타입 안전성을 유지할 수 있습니다. 이는 특히 컬렉션 클래스에서 많이 사용됩니다.

 

1. 제네릭의 기본 개념

 

제네릭 클래스

 

제네릭 클래스를 사용하면, 하나의 클래스가 여러 타입을 처리할 수 있습니다. 예를 들어, 데이터 타입을 명시하지 않고 클래스에 외부에서 타입을 지정할 수 있습니다.

public class Box<T> {
    private T item;  // 타입 T는 외부에서 지정됩니다.

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

T타입 매개변수로, 실제로는 데이터 타입을 의미합니다. 여기서 T는 특정 타입으로 대체됩니다.

예를 들어, TString이 되면 **Box<String>**이 되고, TInteger가 되면 **Box<Integer>**가 됩니다.

 

제네릭 클래스 사용 예시

public class Main {
    public static void main(String[] args) {
        // String 타입의 제네릭 클래스 사용
        Box<String> stringBox = new Box<>();
        stringBox.setItem("Hello");
        System.out.println(stringBox.getItem());  // 출력: Hello

        // Integer 타입의 제네릭 클래스 사용
        Box<Integer> intBox = new Box<>();
        intBox.setItem(123);
        System.out.println(intBox.getItem());  // 출력: 123
    }
}

이처럼 **Box<String>**과 **Box<Integer>**에서 동일한 클래스를 사용하면서도 다른 데이터 타입을 처리할 수 있습니다.

 

2. 제네릭 메서드

 

제네릭은 메서드에서도 사용할 수 있습니다. 제네릭 메서드를 사용하면 메서드가 처리하는 데이터 타입메서드를 호출할 때 지정할 수 있습니다.

 

제네릭 메서드 정의

public class GenericMethodExample {

    // 제네릭 메서드 정의
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }
}

**<T>**는 메서드에서 사용되는 타입 매개변수이며, 메서드를 호출할 때 데이터 타입이 결정됩니다.

위의 예시에서 printArray 메서드다양한 타입의 배열을 처리할 수 있습니다.

 

3. 제네릭의 장점

 

1. 타입 안전성: 제네릭을 사용하면 컴파일 시점에 타입을 체크할 수 있으므로, 런타임에 잘못된 타입을 사용하는 오류를 방지할 수 있습니다.

2. 재사용성: 제네릭을 사용하면 하나의 클래스나 메서드다양한 타입을 처리할 수 있으므로, 코드의 재사용성이 높아집니다.

3. 타입 캐스팅 제거: 제네릭을 사용하면 명시적인 타입 캐스팅이 필요 없으므로, 코드가 더 간결하고 안전해집니다.

 

4. 제네릭의 제한 사항

 

1. 기본 타입 사용 불가: 제네릭은 기본 데이터 타입(primitive type)(예: int, char)을 사용할 수 없습니다. 대신 래퍼 클래스(예: Integer, Character)를 사용해야 합니다.

// 잘못된 사용 (기본 타입 사용 불가)
// Box<int> intBox = new Box<>();  // 오류 발생

// 올바른 사용 (래퍼 클래스 사용)
Box<Integer> intBox = new Box<>();

 

2. 정적(static) 변수 사용 불가: 제네릭 타입은 정적 필드로 사용할 수 없습니다. 정적 필드는 클래스 수준에서 공유되므로, 제네릭 타입을 사용하는 것은 불가능합니다.

public class Box<T> {
    // static T item;  // 오류 발생
}

 

3. 런타임에 타입 정보 손실: 제네릭은 컴파일 시점에만 타입 검사를 수행하며, 런타임에는 타입 정보가 제거됩니다. 이를 **타입 소거(type erasure)**라고 합니다.

 

5. 와일드카드(Generic Wildcards)

 

제네릭에서는 와일드카드를 사용하여 보다 유연한 타입을 처리할 수 있습니다. 와일드카드는 **?**로 표기되며, 특정 범위 내에서 제네릭 타입을 정의할 수 있습니다.

 

? (Unbounded Wildcard)

 

와일드카드 ?모든 타입을 허용합니다.

public void printBox(Box<?> box) {
    System.out.println(box.getItem());
}

이 메서드는 **어떤 타입의 Box**든지 받아서 출력할 수 있습니다.

 

<? extends T> (Upper Bounded Wildcard)

 

<? extends T>T 또는 T의 하위 클래스만 허용합니다.

public void printNumbers(Box<? extends Number> box) {
    System.out.println(box.getItem());
}

이 메서드는 **Number 클래스와 그 하위 클래스(Integer, Double 등)**를 받을 수 있습니다.

 

<? super T> (Lower Bounded Wildcard)

 

<? super T>T 또는 T의 상위 클래스만 허용합니다.

public void addToList(List<? super Integer> list) {
    list.add(123);  // Integer나 그 상위 클래스(List<Number> 등)에만 추가 가능
}

이 메서드는 Integer 클래스와 그 상위 클래스에 값을 추가할 수 있습니다.

 

6. 제네릭 사용 예시 (자주 사용되는 컬렉션과 제네릭)

 

자바에서 제네릭은 컬렉션 클래스에서 가장 많이 사용됩니다. 예를 들어, **List, Map, Set**과 같은 컬렉션 클래스는 제네릭을 사용하여 특정 타입의 데이터를 처리할 수 있습니다.

 

List와 제네릭

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

public class Main {
    public static void main(String[] args) {
        // String 타입을 저장하는 리스트
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");

        for (String item : list) {
            System.out.println(item);
        }
    }
}

제네릭을 사용하지 않을 경우에는 타입 캐스팅을 해야 하므로, 런타임에 타입 오류가 발생할 가능성이 있습니다. 제네릭을 사용하면 컴파일 시점에 타입이 체크되므로, 더 안전한 코드를 작성할 수 있습니다.

 

결론

 

**제네릭(Generic)**은 자바에서 클래스나 메서드다양한 타입을 처리할 수 있도록 하며, 코드의 타입 안전성을 높여줍니다.

제네릭을 사용하면 타입 캐스팅이 필요 없고, 컴파일 시점에 타입 체크가 가능하여 안정성을 보장할 수 있습니다.

와일드카드를 통해 제네릭 타입더 유연하게 정의할 수 있습니다.

제네릭은 특히 컬렉션 클래스에서 많이 사용되며, 코드 재사용성을 극대화할 수 있습니다.

'Java' 카테고리의 다른 글

[Java] Interface  (0) 2024.09.28
[Java]Generic(Interface에서의 활용)  (0) 2024.09.28
[JAVA] Static  (0) 2024.09.24
[JAVA] 빌더(builder)  (0) 2024.09.24
[JAVA] 예외처리(Exception)  (0) 2024.09.24