본문 바로가기

JAVA

JAVA의 정석 - Generics

제네리.html

JAVA의 정석

2018-12-16

제네릭스

와일드 카드

    class Juicer { 
        static Juice makeJuice(FruitBox<Fruit> box) {
            String tmp = '';
            for(Fruit f : box.getList()) tmp += f + " ";
            return new Juice(tmp);
        }
    }

위와 같이 Juicer클래스는 지네릭 클래스가 아닌데다, 지네릭 클래스라고 해도 static 메서드에는 타입 매개변수 T를 매겨변수에 사용할 수 없으므로 아예 지네릭스를 적용하지 않던가, 위의 같이 타입 매개변수 대신, 특정 타입을 지정해줘야 한다.
    지네릭 타입이 다른 것만으로는 오버로딩이 성립하지 않기 때문에 지네릭 타입은 컴파일러가 컴파일할 때만 사용하고 제거해버린다.
    이럴 때 필요한 것이 '와일드 카드' 이다. 와일드 카드는 기호 '?'로 표현하는데, 와일드 카드는 어떠한 타입도 될 수 있다.

    '?'만으로는 Object타입과 다를 게 없으므로, 'extends'와 'subper로 상한과 하한을 제한할 수 있다.
<? extends T> 와일드 카드의 상한제한. T와 그 자손들만 가능
<? super T> 와일드 카드이ㅡ 하한 제한. T와 그 조성들만 가능
<?> 제한 없음. 모든 타입이 가능 <? extends Object 와 동일
#### 지네릭 클래스와 달리 와일드 카드에는 '&'를 사용할 수 없음. 



지네릭 메서드

    메서드의 선언부에 지네릭 타입이 선언된 메서드를 지네릭 메서드라 한다.  
    static 멤버에는 타입 매개변수를 사용할 수 없지만(그래서 와일드 카드를 사용) 메서드에 지네릭 타입을 선언하고 사용하는 것은 가능.  
    지네릭 클래스에 정의된 타입 매개변수와 지네릭 메서드에 정의된 타입 매개변수는 전혀 별개의 것이다.  
    메서드에 선언된 지네릭은 타입은 지역 변수를 선언한 것과 같다고 생각하면 이해하기가 쉽다.(static이건 아니건 상관 없음) 
    즉, 내부 클래스에 선언된 타입 문자가 외부 클래스의 타입 문자와 같아도 구별될 수 있다.

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



지네릭 타입의 형변환

    지네릭 타입과 넌지네릭 타입간의 형변환은 경고가 발생하지만 항상 가능하다.
    다만, 대입된 타입이 다른 지네릭 타입 간에는 형변환이 불가능하다.

    <? extends Object> 인 경우 지네릭으로 형변환이 가능하다.

    Optional<?> EMPTY = new Optional<?>();
    -> Optional<? extends Object> EMPTY = new Optional<>();
    -> Optional<? extends Object> EMPTY = new Optional<Object>();

일반적으로 <?>는 <? extends Object>를 줄여 쓴것이며, <> 안에 생략된 타입은 ‘?’가 아니라 ‘Object’이다.
다만, class Box의 경우 <>는 이다.



지네릭 타입의 제거

    컴파일러는 지네릭 타입을 이용해서 소스파일을 체크하고, 필요한 곳에 형변환을 넣어준다. 그리고 지네릭 타입을 제거한다. 즉, 컴파일된 파일(*.class)에는 지네릭 타입에 대한 정보가 없는 것이다.
    이렇게 하는 이유는 이전 버전의 소스코드와의 호환성을 유지하기 위해서이다.

'JAVA' 카테고리의 다른 글

[JAVA] Reflection 을 이용하여 Method 호출하기  (0) 2020.01.08
[Java] POJO 와 Beans 의 차이점  (0) 2019.08.24
JAVA의 정석 - Thread  (0) 2019.01.13
JAVA의 정석 - 열거형(enums)  (0) 2019.01.13