728x90
불공변성(Invariant)
무공변성이란 상속 관계에 상관없이, 자기 타입만 허용하는 것
공변성(covariant)
공변성은 자기 자신과 자신을 상속한 하위 객체의 타입을 허용하는 것
반공변성(contravariant)
공변성의 반대 개념 자기 자신과 자신이 상속한 부모 객체만 허용하는 것
제네릭은 불공변, 배열은 공변이다.
public static void main(String[] args) {
Object [] objects = new Long[10];
objects[0] = "boo"; // ArrayStoreException 발생
List<Object> objectList = new ArrayList<Long>(); // List 는 제네릭 타입으로 무공변이다. 컴파일 에러 발생
objectList.add("boo");
}
실체화 : 런타임에도 자신이 담기로 한 원소의 타입을 체크함.
배열 : 실체화, 제네릭 : 실체화 불가 타입
이러한 차이 떄문에 배열은 제네릭과 어울리지 않음(배열은 제네릭 불가 타입)
배열 : 공변, 실체화 (컴파일 타임 타입 안전 X, 런타임에 타입 안전)
제네릭 : 불공변, 타입 소거(컴파일 타임 타입 안전, 런타임 타입 안전 X)
제네릭 배열을 허용할 경우, 형변환 코드에서 런타임 ClassCastException 발생 가능 이는 컴파일 타임에 타입 체크를 해서 런타임에 ClassCastException이 발생하는 걸 막겠다는 제네릭의 취지와 맞지 않음
List <String>[] stringLists = new List<String>[1];
List <Integer> intList = List.of(42); //원소가 하나인 List<Integer>
Object[] objects = stringLists; // 배열은 공변이므로 Object 배열에 List<String>배열 할당가능
objects[0] = intList; // 타입이 런타임에 소거되므로 마찬가지로 가능
String s = stringLists[0].get(0); // ClassCastException 발생. int -> String 으로 바꾸려고하기 떄문
배열로 형변혼할 때 제너릭 배열 생성오류나 비검사 형변환 경고가 뜨는 경우 대부분 배열 대신 컬렉션인 List<E>를 사용하면 해결된다, 코드가 조금 복잡해지고 성능이 살짝 나빠지지만 타입안전성과 상호 운용성이 좋아진다.
/*
제네릭 없는 v0 초기버전
choose 호출할때마다 해당 타입으로 형변환 필요
*/
public class Chooser{
private final Object[] choiceArray;
public Chooser(Collection choices){
choicesArra = choices.toArray;
}
public Object choose(){
Random rnd = ThreadLocalRandom.current();
return choiceArray[rnd.nextInt(choiceArray.length)];
}
}
/*v1 제너릭 적용
생성자에서 unchecked cast 비검사 경고 발생
*/
public class Chooser<T>{
private final T[] choiceArray;
public Chooser(Collection<T> choices){
choicesArra = (T[]) choices.toArray;
}
public Object choose(){
Random rnd = ThreadLocalRandom.current();
return choiceArray[rnd.nextInt(choiceArray.length)];
}
}
/*v2 배열 대신 리스트 적용*/
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()));
}
}
'JAVA > Effective Java' 카테고리의 다른 글
item 36) 비트 필드 대신 EnumSet을 사용하라 (0) | 2021.02.06 |
---|---|
item 35) ordinal 메소드 대신에 인스턴스 필드를 사용하라. (0) | 2021.02.06 |
item 27) 비검사 경고를 제거하라 (0) | 2021.01.22 |
item 24) 멤버 클래스는 되도록 static으로 만들라 (0) | 2021.01.17 |
item 25) 톱레벨 클래스는 한 파일에 하나만 담으라 (0) | 2021.01.15 |