본문 바로가기

Dev Book Review/Effective Java

[Effective Java] item29. 이왕이면 제네릭 타입으로 만들라

1. 제네릭클래스로 만드는 방법

a. 클래스 선언에 타입매개변수를 추가한다.

  • 보통 E를 많이 사용한다.
  • 제네릭 필드를 쓴다는 것을 명시하는 것이다.

b. 실체화 불가 타입으로는 배열을 만들 수 없으니 해결한다.

E[] element = new E[DEFAULT_INITAL_CAPACITY]

b-1. 제네릭 배열을 금지하는 제약을 대놓고 우회한다.

E[] elemet = (E[]) new Object[DEFAULT_INITAL_CAPACITY]

비검사 형변환이 프로그램의 타입 안정성을 해치지 않는지를 확인한다. > 이후 @SuppressWarnings 애너테이션으로 해당 경고를 숨긴다.

  • 배열이 private 필드에 저장된다.
  • 클라이언트로 반환되거나 다른 메서드에 전달되는 일이 없다.
  • 배열에 저장되는 원소의 타입은 항상 E 이다.

특징

  • 가독성이 더 좋다. : E 타입만을 받는다는 점을 어필한다.
  • 형변환을 배열 생성시 단한번만 해주면된다.
  • 배열의 런타임 타입이 컴파일타임 타입과 달라 힙오염이 일어날 수 있다.

b-2. 배열 필드의 타입을 Object[]로 바꾼다.

E result = (E) elements[--size];

E가 실체화 불가 타입이므로 컴파일러는 런타임에 이뤄지는 형변환이 안전한지 증명할 방법이 없다. > 이후 비검사 형변환을 수행하는 할당문에서만 경고를 숨긴다.

특징

  • 배열에서 원소를 읽을 떄마다 형변환 해주어야 한다.
  • 힙오염이 해가되지 않는다.

 

2. 제네릭 배열을 사용하는 이유

  • 자바가 리스트를 사용하는게 항상 가능하지도, 꼭 더 좋은 것도아니다. 리스트도 결국은 기본타입인 배열을 사용해 구현해야하기 때문이다.
  • 성능향상의 이슈로 배열을 사용할 수 있다.
  • 제네릭타입의 타입매개변수에는 primitive 타입을 사용할 수 없다. 박싱된 기본타입으로 우회할 수 있긴하다.

 

3. 한정적 타입 매개변수

class DelayQueue<E extends Delayed> implements BlockingQueue<E>

Delayed.class의 하위타입만 받는다는 의미이다. (모든 타입은 자기 자신의 하위 타입)

ClassCastException을 걱정할 필요가 없다.