경계의 경계

자바의 제네릭 (Generic) 본문

Java

자바의 제네릭 (Generic)

gigyesik 2024. 2. 28. 02:43

제네릭 (Generic) 이란 무엇인가

자바는 타입 언어 (Typed Language) 이다. 제네릭은 서로 다른 타입을 가지고 연산을 할 수 있게 해주는 새로운 타입을 의미한다.

서로 다른 타입을 최상위 객체인 Object 객체를 가지고 연산하게 하므로, 타입 안정성이 떨어질 수 있다. 그에 따른 안정성 보강 방법 또한 가지고 있다.

제네릭의 유형

제네릭 클래스 (Generic Class)

  • 아래 코드에서 제네릭 타입으로 선언한 T, U 에는 미리 알고있지 않던 타입이 대입되더라도 코드가 동작한다.
  • 파라미터 타입에 int, char, double 과 같은 이른바 원시 타입 (primitive type) 은 대입할 수 없다.
  • 아래 코드처럼 한 제네릭 클래스에 여러 개의 제네릭 파라미터를 선언하는 것도 가능하다.
public class GenericTest2<T, U> {
    T obj1;
    U obj2;

    GenericTest2(T obj1, U obj2) {
        this.obj1 = obj1;
        this.obj2 = obj2;
    }

    public void print() {
        System.out.println(obj1);
        System.out.println(obj2);
    }

    public static void main(String[] args) {
        GenericTest2<String, Integer> obj = new GenericTest2<>("ABC", 10);

        obj.print(); // ABC 10
    }
}

제네릭 메서드 (Generic Method)

  • 제네릭 클래스처럼 메서드의 파라미터나 리턴 또한 제네릭으로 선언할 수 있다.
  • 마찬가지로 제네릭으로 선언한 변수에는 레퍼런스 타입 (reference type) 만 사용할 수 있으며, 원시 타입은 사용할 수 없다.
public class GenericTest4<T> {
    T obj;
    GenericTest4(T obj) { this.obj = obj; }
    public T getObj() { return this.obj; }

    public static void main(String[] args) {
        GenericTest4<Integer> intObj = new GenericTest4<>(10);
        System.out.println(intObj.getObj()); // 10

        // GenericTest4<int> iObj = new GenericTest4<int>(22); // primitive type 불가
        GenericTest4<ArrayList<int[]>> aiObj = new GenericTest4<>(new ArrayList<>()); // ArrayList 가 이미 referenced type 이므로 가능

        GenericTest4<String> stObj = new GenericTest4<>("ABC");
        System.out.println(stObj.getObj()); // ABC

        // intObj = stObj; // error
    }
}

제네릭 컨벤션 (Convention)

제네릭 파라미터를 선언할 때는 naming convention 이 존재한다.

필수적으로 따라야 하는 것은 아니지만, 타입 안정성을 해칠 수 있는 제네릭이므로 일관성 있는 구현이 필요하다.

  • T - Type
  • E - Element
  • K - Key
  • N - Number
  • V - Value

제네릭 사용의 장점

  • 같은 로직 코드를 다른 타입에도 적용할 수 있으므로 재사용성이 증가한다.
  • 컴파일 타임에 에러를 발생시켜 타입 안정성도 어느 정도 보장해 준다.
  • 데이터를 조회할 때마나 타입 캐스팅을 시도할 필요 없다.
public class GenericTest5 {
    // 원시타입이 아닌 타입을 비교하려면 Comparable 클래스를 상속해야함
    public static <T extends Comparable<T>> void sortGeneric(T[] array) {
        // Bubble Sort
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j].compareTo(array[j+1]) > 0) swap(j, j+1, array);
            }
        }

        // Print
        for (T i : array) {
            System.out.println(i + ", ");
        }
        // 줄바꿈
        System.out.println();
    }

    public static <T> void swap(int i, int j, T[] array) {
        T t = array[i];
        array[i] = array[j];
        array[j] = t;
    }

    public static void main(String[] args) {
        Integer[] integers = {20, 30, 50, 40, 10};
        Character[] characters = {'c', 'b', 'a', 'd', 'e'};
        String[] strings = {"ABC", "CBA", "BAC", "CAB", "ACB"};

        sortGeneric(integers); // 10 20 30 40 50
        sortGeneric(characters); // a b c d e
        sortGeneric(strings); // ABC ACB BAC CAB CBA
    }
}

References

'Java' 카테고리의 다른 글

자바의 JVM  (0) 2024.03.01
자바의 Stream  (1) 2024.02.29
자바의 네트워킹과 소켓 통신  (1) 2024.02.27
자바의 직렬화 (Serialization)  (0) 2024.02.22
자바의 Collection Framework  (1) 2024.02.20