[Java] 제네릭스(Generics) 사용이유와 특징, 제한된 타입 파라미터

    제네릭스 사용 이유

    제네릭스를 알려면 우선 타입변수를 알아야 한다. 
    타입변수는 일반적으로 제네릭스를 사용하는 ArrayList, Set 등 컬렉션에서 볼 수 있는데, 아래 보이는 <E> 가 타입 변수다.

     

    제네릭스를 사용하지 않으면 모든 형태의 데이터를 담을수 있게 Object로 되어 있어야 하고 데이터를 사용하려면 Object의 데이터를 꺼내서 형변환이 필요하고, 또 다른 타입의 데이터를 넣었을때 형변환해서 사용하기 전까지 알수가 없다.

    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);

     

     

    하지만 제네릭스를 사용하면 형변환 할필요가 없고, 데이터를 add 하는 시점에서 데이터 타입이 String이 아니라면 에러가 난다.

    List<String> list = new ArrayList<String>();
    list.add("hello");
    String s = list.get(0);   // no cast

     

    그래서 제네릭스의 사용 이유는 아래와 같이 정의된다.

     

    제네릭스는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크를 해주는 기능이다.
    객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.

     

     

    제네릭스 특징

    1. 원시타입(Raw Type)

    아래와 같이 타입 변수가 있는 클래스나  인터페이스를 타입변수 없이 객체 생성을 했을 때 이것을 원시 타입이라고 하는데, 제네릭스 없이 객체 생성이 허용되는 이유는 JDK 이전 버전하고 호환성을 위해서 그랬다고 한다. 제네릭스 없이 객체 생성을 하면 타입 Object를 제공한다. 주의할점은 제네릭스가 없는 클래스나 인터페이스를 객체 생성 했을때 원시 타입이라고 부르지 않는다.

    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);

     

     

    2. 타입 변수 이름 규칙

    타입 변수는 말 그대로 변수여서 어떤 이름으로도 사용이 가능하다 하지만 일반적으로 사용되는 규칙이 있다. 일반 변수와는 달리 단일 대문자 이여야 한다.

    • E - Element (used extensively by the Java Collections Framework)
    • K - Key
    • N - Number
    • T - Type
    • V - Value
    • S,U,V etc. - 2nd, 3rd, 4th types

    3. 타입 변수(Type Parameter)와 타입 인수(Type Argument) 

    많은 개발자들이 두 용어를 같은 의미로 사용하지만, 타입 변수와 타입 인수는 엄연히 다른 용어이다. 

    타입 변수는 ArrayList 클래스를 만들때 ArrayList<E> 에서 E가 타입 변수이고  타입 인수는 ArrayList를 사용할 때 ArrayList<Integer> 에서 Integer가 타입 인수이다. 

     

    4. 다이아몬드(The Diamond)

    제네릭스는 JDK1.5부터 나왔고 JDK 1.7부터 변수 생성 시점에서 타입 인수를 지정하면 객체 생성 부분에서 타입인수를 지정하지 않고 꺽쇠 괄호 <> 만 있으면 객체가 생성된다. 이것을 비공식적으로 다이아몬드라고 한다.

    //JDK 1.7 부터 가능
    ArrayList<Integer> list = new ArrayList<>();

     

    5. 타입을 여러개 지정할 수 있다.

    아래 소스 처럼 , 단위로 여러개 타입 변수를 지정할 수 있다.

    public class MultipleTypeParameter<T1, T2, T3, T4> {
        private T1 value1;
        private T2 value2;
        private T3 value3;
        private T4 value4;
    
        MultipleTypeParameter(T1 value1, T2 value2, T3 value3, T4 value4) {
            this.value1 = value1;
            this.value2 = value2;
            this.value3 = value3;
            this.value4 = value4;
        }
    }
    
    MultipleTypeParameter<String, Integer, Double, Character> multipleTypeParameter;
    multipleTypeParameter = new MultipleTypeParameter<>("str", 1, 1.0, 'C');

     

    5. 매개변수화된 타입(Parameterized type)

    타입 인수로 매개변수화된 타입을 사용할 수 있다. 아래 코드에선 매개변수화된 타입이 ArrayList<Integer> 이다.

    Map<Integer, ArrayList<Integer>> map = new HashMap<>();

     

    6. static 멤버 변수에는 사용될 수 없다.

    static 멤버변수는 메소드 영역에서 공유되는 변수이기 때문에 여러 객체에서 공유되어야 하는데 타입 변수는 객체생성때마다 부여 받는 타입이기 때문이다. 즉 타입 변수는 인스턴수 변수이다.

     

    제한된 타입 파라미터(Bounded Type Parameters)

    타입 인수로 특정화된 타입이 아니라 특정 제한된 타입을 사용할 수 있도록 할 수 있다. 예를 들어 숫자 타입만을 제한두고 싶다고 했을때 모든 숫자의 상위 클래스인 Number의 하위 클래스(Integer, Double, Float 등)의 타입을 제한해서 사용할 수 있도록 허용할 수 있다.

    제한된 타입 파라미터를 사용하려면 타입 변수 extends 상위 클래스 or 인터페이스 이다. 주의할 점은 인터페이스라고해서 implements 를 쓰지 않는다.

    public class NumberClass<T extends Number> {
        T numberValue;
    
        public NumberClass(T numberValue) {
            this.numberValue = numberValue;
        }
    
        public T getNumberValue() {
            return numberValue;
        }
    }

    <T extends Number> 선언으로 T 타입은 Number 클래스의 하위 클래스 타입만 가능하다는 뜻이다.

    public class TestMain {
        public static void main(String[] args) {
            NumberClass<Integer> intNumber = new NumberClass<>(10);
            NumberClass<Double> doubleNumber = new NumberClass<>(10.5);
            NumberClass<Float> floatNumber = new NumberClass<>(10.5f);
            //NumberClass<String> stringValue = new NumberClass<>("str); //에러
        }
    }

    Number의 하위클래스만 가능하므로 타입인수로 Integer, Double, Float은 가능하지만 String은 불가능하다.

     

     

    참고 

    - 남궁성 / 자바의 정석

    - https://docs.oracle.com/javase/tutorial/java/generics/types.html

     

     

     

    댓글

    Designed by JB FACTORY