배열과 제네릭의 차이
// 컴파일 에러가 발생하지 않는다.
Object[] objectArray = new String[1];
// 컴파일 에러가 발생한다.
List<Object> objectList = new ArrayList<String>()
배열에서는 Sub가 Super의 하위 타입이라면 Sub[]는 Super[]의 하위타입이 된다. 리스트에서는 List<Sub>가 List<Super>의 하위타입이 아니다. 따라서 위의 코드를 보면 배열에서는 가능한 코드가 리스트에서는 컴파일 에러가 발생한다. 배열이 더 유연한 코드를 제공하는거 같지만 실제로는 위험한 코드를 허용해주는 것이다. 배열의 저러한 특성때문에 아래의 코드같이 런타임에 문제가 생길 수 있다.
// 런타임에서 발생
Object[] objectArray = new String[1];
objectArray[0] = 3;
제네릭 적용하기
public class Chooser {
private final Object[] choiceArray;
public Chooser(Collection choices) {
choiceArray = choices.toArray()
}
public Object choose() {
Random rnd = ThreadLocalRandom.current();
return choiceArray[rnd.nextInt(choiceArray.length)];
}
}
Collection 타입의 인스턴스를 받아서 랜덤한 객체를 하나씩 뽑아내는 Chooser 클래스가 있다. 하지만 해당 클래스는 choose 메소드를 호출할 때마다 반환된 Object를 원하는 타입으로 변환해야 한다. 이 클래스를 제네릭을 사용하더 개선해보고자 한다.
public class Chooser<T> {
private final T[] choiceArray;
public Chooser(Collection<T> choices) {
choiceArray = (T[]) choices.toArray();
}
public T choose() {
Random rnd = ThreadLocalRandom.current();
return choiceArray[rnd.nextInt(choiceArray.length)];
}
}
제네릭을 사용하여 Chooser 클래스를 생성할때 타입 파라미터를 전달하여 choose 때마다 형변환을 할 필요가 없도록 하였다. 하지만 choiceArray = (T[]) choices.toArray(); 부분에서 형변환 경고가 발생한다. 물론 이를 무시할 수 있겠지만, 추후 런타임에서 문제가 생길 수 있기때문에 배열 대신 List를 사용하여 형변환 경고를 없애보고자 한다.
public class Chooser<T> {
private final List<T> choiceList;
public Chooser(Collection<T> choices) {
choiceList = new ArrayList<>(choices);
}
public T choose() {
Random rnd = ThreadLocalRandom.current();
return choiceList.get(rnd.nextInt(choiceList.size()));
}
}
728x90
'STUDY > 이펙티브자바' 카테고리의 다른 글
5-5) 한정적 와일드카드를 사용해 유연성을 높혀라 (0) | 2022.10.20 |
---|---|
5-4) 이왕이면 제네릭 타입으로 만들라 (0) | 2022.10.19 |
5-2) 비검사 경고를 제거하라 (0) | 2022.10.18 |
5-1) 제네릭 클래스의 raw type은 사용하지 마라 (1) | 2022.09.23 |
4-10) 멤버 클래스는 되도록 static으로 만들어라 (0) | 2022.09.19 |