본문 바로가기

컴퓨터/JAVA

자바 고급 스터디 5. generic type erasure(제네릭 타입 소거)

반응형

자바 고급 스터디 목록

공부 시간 : 2021/04/06 24:00 ~ 24:40, 04/07 11:00 ~

5주차. generic type erasure(제네릭 타입 소거)에 대해서 설명해보세요.

제네릭 이란?

자바에서 제네릭이란 클래스나 메소드에 사용할 내부 데이터 타입을 컴파일 시점에 미리 정하는 방법이다. 제네릭을 사용함으로써 얻을 수 있는 장점은 무엇일까?

  1. 객체의 타입 안정성을 높힐 수 있다.
  2. 반환값의 타입 변환, 타입 검사에 대한 것을 생략할 수 있다.
public class dd<T> {
    List<T> list = new ArrayList<>();
    List<Object> list = new ArrayList<>();
}

제네릭을 위와 같이 사용 하면 제네릭을 사용하는 장점을 잘 살릴 수 있을지 생각해보자.

먼저 타입안정성에 대한 부분이다. 타입 안정성을 좀 더 풀어서 설명하면, 컴파일시에 잘못된 타입을 체크 할 수 있는지 여부이다. Integer 값을 입력받는 리스트가 있다고 생각해보자.

    List<Integer> integer_list = new ArrayList<>();
    integer_list.add("1");

아래와 같이 사용하면 "string" 부분에 잘못된 타입이 들어갔다!! Integer 달라고 했는데 왜 String 주냐? 라고 IDE가 친절하게 알려줄 것이다.

하지만 아래 상황은 어떨까?

    List<Object> integer_list=new ArrayList<>();
    integer_list.add(1);
    integer_list.add("1");

IDE가 알려주지 않는다. "1"은 list에서 꺼내서 실제 작동될때(런타임) 시점에 예기치 못한 에러가 발생되거나, 올바르지 않는 결과를 초래 할 것 이다.

아래와 같이 타입체크를 하는 과정을 거치면 예기치 못한 에러, 올바르지 않은 결과를 방지 할 수 있을 것이다.

    List<Object> integer_list=new ArrayList<>();
    integer_list.add(1);
    integer_list.add("1");

    if(integer_list.get(1)instanceof Integer)

하지만 제네릭을 올바르게 사용하는 것이 더 좋은 방법일 것이다. 결론은 제네릭을 올바르게 사용하면

  1. 타입안정성을 높힐 수 있고
  2. 반환값의 타입 변환, 타입 검사에 대한 것을 생략할 수 있다.

제네릭 타입 소거

  1. T 와 같이 타입을 직접 명시하지 않은 타입 매개변수를 로 타입이라고 한다. 로 타입은 컴파일시에 Object로 대체된다.

오라클 공식문서 중 일부 내용 :
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.

  1. 로 타입을 Object로 대체 한 후 필요시에 Casting 한다.
  2. 타입안정성을 위해 Bridge Method를 만들수도 있다.
public class IntegerStack extends Stack<Integer> {
    public Integer push(Integer value) {
        super.push(value);
        return value;
    }
}

위와 같이 어떠한 클래스나, 인스턴스를 상속 혹은 구현할때 bridge mothod를 만들게 되는데,

public class IntegerStack extends Stack {
    // Bridge method generated by the compiler

    public Integer push(Object value) {
        return push((Integer) value);
    }

    public Integer push(Integer value) {
        return super.push(value);
    }
}

위와 같이 Object를 Integer로 캐스팅 해줌으로써 제네릭소거로 인해 발생하게 될 타입불일치를 방지해준다.

제네릭을 사용할때는 array 대신 List를 사용하자.

이펙티브 자바에 나와있는 내용으로, 간단하게 결론을 말하면 제네릭은 타입소거를 하기때문에, 런타임시가 아닌 컴파일타임에 타입추론이 가능하다.
자바 제네릭의 장점과 타입추론을 적극적으로 활용하기 위해서는 런타임에 타입을 추론이 되는 Array보다는 컴파일 타임에 타입을 추론하는 List와 함께 사용하는 것이 좋다.

참고 사이트 :

반응형