자바 (Java)/요약

Chpt 12. 지네릭스, 열거형, 애너테이션 - 주제 1. 지네릭스

학듄 2023. 11. 10. 12:32
728x90

1. 지네릭스의 장점

 

지네릭스는 컴파일 시 타입 체크를 해주는 기능이다. 지네릭스는 다음과 같은 장점에 의해 도입되었다.

 

(1) 타입 안정성을 제공한다.
(2) 타입체크, 형변환 생략으로 코드가 간결해진다.

 

(1)은 타입 체크를 강화해 형변환 에러를 방지해준다. 모든 타입의 객체를 담을 수 있는 ArrayList를 예로 들어보겠다.

 

ArrayList list = new ArrayList();

list.add(10); // list.add(new Integer(10));

list.add(20); 

list.add("30"); // String 타입

Integer i = (Integer) list.get(2);

 

위 코드를 실행하면 컴파일은 되지만 형변환 실행 에러가 발생한다. 실행 도중 에러가 발생하게 되면 컴파일 에러와 달리 수정이 불가하고 프로그램이 비정상적으로 종료된다. 즉, 지네릭스는 런타임 에러를 컴파일 에러로 변경하기 위한 노력이다.

 

 

비슷한 예로 런타임 에러를 방지하기 위해 String str = null;로 참조하는 것보다 배열의 길이가 0인 배열({}, new Object[0])을 참조하는 것이 좋다. null을 참조했을 때 str.length()를 호출하면 NullPointerExcpetion(RuntimeException)이 발생한다.

 

컬렉션 클래스나 여러 타입을 다루는 메서드의 경우 매개변수나 리턴타입으로 Object 타입을 많이 사용했다. 지네릭스 도입 이후 <>를 사용해 타입을 제한해 주어야 한다.

 

[예 1-1]

 

  지네릭스 도입 전 지네릭스 도입 후
메서드 get의 반환 타입 Object E
형변환 필요 여부 O X

 

 

[예 1-2] Iterator<E>

 

Iterator<Student> it = list.iterator();

while(it.hasNext()) {

    System.out.println(it.nextI().name);

}

 

위 코드의 경우 지네릭스가 없다면 Student s = (Student) it.next() 과 같이 형변환한 후 name 필드에 접근해야 한다.

 

[예 1-3] HashMap<K, V>

 

public class HashMap<K, V> extends AbstractMap<K, V> {

    ...

    public v get(Object key) { ... }

    ...

}

 

HashMap<String, Student> map = new HashMap<String, Student>();

map.put("student1", new Student( ... )); 

Student s1 = map.get("student1") // 형변환 불필요

2. 지네릭스 용어

 

다음은 지네릭스에서 사용되는 용어이다.

 

class Box<T> {}

 

T 타입 (매개)변수
T 자체 타입 문자 (아무 문자나 사용해도 된다.)
Box 원시 타입
Box<T> 지네릭 클래스

 

지정해야 할 타입 매개변수가 여러 개인 경우 콤마(,)를 통해 구별해준다. 

 

Box<String> box = new Box<String>();

 

String 대입된 타입
<String> 지네릭 타입
Box<String> 지네릭 타입 호출

 

3. 지네릭스 제약

 

(1) static 멤버는 타입 매개변수(T)를 사용할 수 없다. 
(2) instanceof는 타입 매개변수(T)를 사용할 수 없다. 
(3) 지네릭 배열은 생성할 수 없다.
(4) 지네릭 객체는 생성할 수 없다.

 

(1): T가 인스턴스 변수로 간주되기 때문이다.

(2)~(4): 모두 new 연산자를 사용하기 때문이다. 

 

4. 지네릭 메서드

지네릭 타입이 선언부에 있는 메서드를 지네릭 메서드라고 한다. 지네릭 메서드는 다음과 같은 특징을 갖고 있다.

 

(1) 지네릭 클래스가 아닌 클래스에도 정의할 수 있다.
(2) 지네릭 클래스의 지네릭 타입과 지네릭 메서드의 지네릭 타입은 서로 다른 것이다.
(3) 지네릭 메서드에 선언된 지네릭 타입은 지역변수이다.

 

class FruitBox<T> {

    ...

    static <T> void sort(List<T> list, Comparator<? super T> c) {

        ...

    }

}

 

이런 메서드를 호출할 때 Arrays.<Integer>sort(...) 처럼 타입 매개 변수에 타입을 대입해야 하지만 생략 가능하다. 에러가 나는 경우가 간혹 있지만 이때는 그냥 붙여주도록 하자.

 

[참고] 타입 (매개)변수 (T) vs. 지네릭 타입 (<T>)

static 멤버에는 T를 못 쓰지 <T>는 사용할 수 있다. 둘을 혼동하지 않도록 하자.

반응형