티스토리 뷰

Java+Spring/Java

[Java]자바 제네릭(Generic)

Vagabund.Gni 2024. 7. 21. 20:39
728x90
반응형

목차

     

    자바 제네릭(Generic)은 자바 5에서 도입된 기능으로,

     

    클래스, 인터페이스, 메서드의 데이터 타입을 지정하지 않고 사용할 수 있게 해 준다.

     

    제네릭을 사용하면 코드의 재사용성이 높아지고, 타입 안전성이 보장되며, 코드의 가독성도 향상되는 장점이 있다.

     

    이 글에서는 제네릭의 기본 개념에서 시작해 사용법, 예시 등을 간결히 정리한다.

     

    Basic Concepts

     

    앞서 설명했듯이 제네릭은 클래스, 메서드 등에서 사용할 데이터 타입을 미리 지정하지 않고,

     

    나중에 실제 사용할 때 구체적인 타입을 지정하도록 해준다. 이는 코드 재사용성을 크게 높일 수 있다.

     

    제네릭 타입을 사용하는 클래스나 메서드는 다음과 같은 형태를 가진다.

     

    class 클래스이름<T> {
        private T 변수;
    
        public T 메서드이름() {
            // 메서드 구현
        }
    
        public void set변수(T 변수) {
            this.변수 = 변수;
        }
    }

    여기서 T는 타입 파라미터(Type Parameter)라고 하며, 실제 사용 시 구체적인 타입으로 대체된다.

     

    Generic Classes

     

    제네릭 클래스를 정의하면, 클래스 내부에서 사용할 데이터 타입을 인스턴스화할 때 지정할 수 있다.

     

    예를 들면 다음과 같은 제네릭 클래스를 정의하면,

     

    class Box<T> {
        private T content;
    
        public T getContent() {
            return content;
        }
    
        public void setContent(T content) {
            this.content = content;
        }
    }

    'Box' 클래스를 다양한 타입으로 인스턴스화해서 사용할 수 있게 된다.

     

    Box<String> stringBox = new Box<>();
    stringBox.setContent("Hello");
    String content = stringBox.getContent();
    
    Box<Integer> intBox = new Box<>();
    intBox.setContent(123);
    Integer number = intBox.getContent();

     

    Generic Methods

     

    제네릭 메서드는 메서드 레벨에서 타입 파라미터를 사용할 수 있게 해 준다.

     

    이는 클래스의 타입 파라미터와는 독립적이다.

     

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

    위와 같이 정의하면 'printArray'메서드를 다양한 타입의 배열에 대해 사용할 수 있다.

     

    String[] stringArray = {"Hello", "World"};
    Utility.printArray(stringArray);
    
    Integer[] intArray = {1, 2, 3, 4, 5};
    Utility.printArray(intArray);

     

    Generic Interfaces

     

    제네릭은 인터페이스에서도 사용할 수 있는데,

     

    interface Repository<T> {
        void save(T entity);
        T findById(int id);
    }

    이 인터페이스를 구현하는 클래스에서 구체적인 타입을 지정해야 한다.

     

    class UserRepository implements Repository<User> {
        @Override
        public void save(User user) {
            // 저장 로직
        }
    
        @Override
        public User findById(int id) {
            // 조회 로직
            return new User();
        }
    }

     

    Bounded Types

     

    자바 제네릭을 사용할 때, 특정 타입만 허용하도록 제한하는 것도 가능하다.

     

    이는 'extends'키워드를 사용해 상위 타입을 지정함으로써 이루어진다.

     

    class NumberBox<T extends Number> {
        private T number;
    
        public void setNumber(T number) {
            this.number = number;
        }
    
        public T getNumber() {
            return number;
        }
    }

    위와 같이 구현하면 'NumberBox'는 'Number'의 하위 클래스만 허용한다.

     

    NumberBox<Integer> intBox = new NumberBox<>();
    intBox.setNumber(123);
    
    NumberBox<Double> doubleBox = new NumberBox<>();
    doubleBox.setNumber(45.67);
    
    // NumberBox<String> stringBox = new NumberBox<>(); // 오류 발생

     

    Wildcards

     

    와일드카드 '?'는 특정 타입이 아닌 불특정 타입, 즉 모든 타입을 나타낼 때 사용된다.

     

    주로 제네릭 메서드나 컬렉션에서 사용되며, 타입 파라미터와의 비슷하게 사용할 수 있다.

     

    제한 없는 와일드카드:

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

    상한, 하한 경계 있는 와일드카드:

     

    public void printNumbers(List<? extends Number> list) {
        for (Number number : list) {
            System.out.println(number);
        }
    }
    
    public void addNumbers(List<? super Integer> list) {
        list.add(1);
        list.add(2);
    }

     

    예를 들어 아래와 같이 와일드카드를 이용해 메서드를 정의한다면,

     

    public class WildcardExample {
        public void printList(List<?> list) {
            for (Object element : list) {
                System.out.println(element);
            }
        }
    
        public void printNumbers(List<? extends Number> list) {
            for (Number number : list) {
                System.out.println(number);
            }
        }
    }

    아래와 같이 호출해 사용할 수 있다.

     

    WildcardExample example = new WildcardExample();
    List<Integer> intList = Arrays.asList(1, 2, 3);
    example.printList(intList);
    example.printNumbers(intList);

     

    Limitation of Generics

     

    그렇다고 모든 상황에서 제네릭을 사용할 수 있는 건 아니다. 아래와 같은 제한사항이 있다.

     

    • 기본 타입 사용 불가
      제네릭 타입 파라미터로는 기본 타입(int, char)등을 사용할 수 없다. 대신 박싱된 타입(Integer, Character)을 사용해야 한다.
      왜냐하면 기본 타입은 원시 타입(Primitive Type)으로, 객체가 아닌 메모리 상의 값 자체를 나타내기 때문인데, 제네릭 타입은 기본적으로 객체를 다루기 위해 설계되었기 때문이다.
    • 정적 콘텍스트에서 사용 제한
      정적 변수나 정적 메서드에서는 제네릭 타입 파라미터를 사용할 수 없다.
      제네릭 타입 파라미터는 인스턴스화된 객체의 타입 정보를 기반으로, 객체가 생성될 때 구체적인 타입으로 대체된다. 반면 정적 변수나 메서드는 클래스 레벨에서 동작하며, 클래스가 로드될 때 메모리에 적재되어야 하기 때문에 제네릭 타입 파라미터를 사용할 수 없다.
    public class MyClass<T> {
        // static T myVar; // 오류 발생
        // static T myMethod() { return null; } // 오류 발생
    }

     

    • 인스턴스 생성 불가
      제네릭 타입 파라미터를 사용해서 인스턴스를 생성할 수 없다.
      제네릭 타입 파라미터는 컴파일 타임에 구체적인 타입으로 대체되고, 런타임에는 타입 정보가 소거된다. 즉, 제네릭 타입 파라미터는 컴파일 타임에만 존재하고 런타임에는 구체적 타입 정보가 남아있지 않게 된다. 객체를 생성하기 위해서는 해당 타입의 구체적인 클래스 정보가 필요하지만, 제네릭 타입 파라미터는 런타임에 구체적인 타입 정보를 알 수 없기 때문에 인스턴스를 생성할 수 없다.
    public class MyClass<T> {
        // T myVar = new T(); // 오류 발생
    }

     

    • 배열 생성 불가
      제네릭 타입 파라미터로는 배열을 생성할 수 없다.
      자바에서 배열은 런타임에 자신의 타입을 알고 있으며, 이를 통해 타입 체크를 수행한다. 반면 제네릭은 컴파일 타임에만 타입 정보를 사용하고, 런타임에는 타입 정보가 소거된다. 제네릭 타입 파라미터로 배열을 생성하면, 배열의 런타임 타입 정보와 제네릭 타입 정보 간의 불일치가 발생할 수 있다. 이는 타입 안정성을 해칠 수 있으므로 자바는 제네릭 타입 파라미터로 배열을 생성하는 것을 허용하지 않는다.
    public class MyClass<T> {
        // T[] myArray = new T[10]; // 오류 발생
    }

    다만 배열이 아닌 리스트와 같은 컬렉션 클래스를 사용하면 타입 파라미터를 사용할 수 있다.

     

    public class MyClass<T> {
        private List<T> myList = new ArrayList<>();
    
        public void addElement(T element) {
            myList.add(element);
        }
    
        public T getElement(int index) {
            return myList.get(index);
        }
    }
    반응형
    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/10   »
    1 2 3 4 5
    6 7 8 9 10 11 12
    13 14 15 16 17 18 19
    20 21 22 23 24 25 26
    27 28 29 30 31
    글 보관함