프로그래밍(~2017)/자바

자바 제네릭 관련 정리

단세포소년 2011. 8. 18. 12:11
반응형

Generics

제너릭 타입(Generic Types)은 주로 자바 컬렉션에서 많이 사용되고 있다. 컬렉션은 자료구조이다. 컬렉션에는 어떤 자료를 담을지 알 수 없으므로 최상위 객체인 Object형태로 저장되고 관리되도록 설계되어 있다. 하지만, 의도하지 않은 자료형이 담기는 경우도 발생하게 된다. 이 때의 오류는 컴파일시에는 알 수가 없고 실행을 시켜보아야만 알 수 있다는 것이 문제점이었다. 제너릭 타입을 사용하면 프로그래머가 원하는 객체의 타입을 명시해서 의도하지 않은 객체는 저장될 수 없도록 컴파일시에 오류를 확인할 수있게 된다.

제너릭클래스 정의하기

제네릭 클래스를 정의하는 방법은 일반적인 클래스를 정의하는 것과 동일하다. 다만, 클래스명 뒤에 <제너릭타입, ...>이라고 덧붙여 준다.

public class Box<T> {
    private T t; // T stands for "Type"
    public void add(T t) {
        this.t = t;
    }
    public T get() {
        return t;
    }
}

제너릭 클래스 선언 / 생성

일반적인 클래스와 동일하게 선언하고 생성할 수 있다. 다만, 클래스명 뒤에 <제너릭타입>을 덧붙여주면 된다.

Box<Integer> integerBox;
integerBox = new Box<Integer>();

제너릭 타입에 사용되는 파라미터

타입 매개변수는 하나의 대문자를 사용한다. 이들은 파일시스템에 실재로 존재하는 것은 아니다. 즉, T.java 라던지 T.class라는 파일은 없다. 타입매개변수를 여러개 사용할 수도 있지만 하나의 선언문에서 두 번 사용될 수는 없다. 즉, Box<T, U>는 가능하지만 Box<T, T>는 안된다.

  • E - Element (자바의 컬렉션에서 널리 사용되고 있다.)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types

제너릭 메서드 / 제너릭 생성자

타입 매개변수가 메서드의 선언 등에 사용될 수도 있다. 단, 매개변수의 범위가 메서드의 블록 이내로 한정된다.

public class Box<T> {
    private T t;
    public void add(T t) {
        this.t = t;
    }
    public T get() {
        return t;
    }
    public <U> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }
    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.add(new Integer(10));
        integerBox.inspect("some text");
    }
}

타입 파라미터 제한하기

타입매개변수를 적당히 제한해야 할 경우에는 extends ...를 사용한다. extends 뒤에는 클래스명일 수도 있고 인터페이스명일 수도 있다. 아래의 예에서는 U가 Number의 하위 클래스이어야 한다.

public <U extends Number> void inspect(U u){
    System.out.println("T: " + t.getClass().getName());
    System.out.println("U: " + u.getClass().getName());
}

여러 조건을 만족시켜야 할 경우에는 &를 사용할 수도 있다.

<U extends Number & MyInterface>

하위타입

이제, 객체지향의 '이다 (is a)'관계를 생각해 볼 때다. Integer는 Object에 할당할 수 있다. '이다'관계에 있기 때문이다. 마찬가지로 Number에 Integer를 할당할 수도 있고, Double을 할당할 수도 있다. 이러한 관계는 제너릭에서도 마찬가지이다.

Box<Number> box = new Box<Number>();
box.add(new Integer(10)); // OK
box.add(new Double(10.1)); // OK

그러나,

public void boxTest(Box<Number> n){
    // method body omitted 
}

이 경우에 Box<Integer>와 Box<Double>는 매개변수로 전달되지 않는다. 이것들은 Box<Number>의 하위타입이 아니기 때문이다. 꽤나 논리적인 내용 전개가 필요하지만 뭔말인지 헷갈리므로 그냥 패스~

와일드카드

?는 알 수 없는 타입을 뜻한다.

  • <?> - 모든 객체 자료형, 내부적으로는 Object로 인식한다.
  • <? super 객체자료형> - 명시된 객체자료형과 그 상위 객체, 내부적으로는 Object로 인식한다.
  • <? extends 객체자료형> - 명시된 객체 자료형과 이를 상속한 하위객체, 내부적으로는 명시된 객체 자료형으로 인식한다.

타입제거

제너릭 타입이 인스턴스화 될 때, 컴파일러는 타입파라미터와 관련된 정보를 제거한다. 제너릭을 사용하기 이전의 라이브러리 등과의 호환성을 유지하기 위해서이다.

출처 : http://shonm.tistory.com/category/JAVA/%EC%A0%9C%EB%84%A4%EB%A6%AD%20%EA%B4%80%EB%A0%A8%20%EC%A0%95%EB%A6%AC

반응형