자바 1.5부터 제네릭을 사용할 수 있게되었습니다.
리스트, 셋 등에서 많이 사용해보셨겠지만, 제네릭은 자료형을 매개로 받아 지정하는 것을 이야기 합니다.
public static void main(String[] args){
class test<T> {
private T data;
public test(T data) {
this.data = data;
}
}
test test = new test<String>("text");
System.out.println(test);
}
이런식으로 말이죠.
이 제네릭은 무인자로도 사용이 가능합니다.
test test = new test("text");
이렇게 말이죠. 컴파일 에러가 뜨지 않습니다. 하지만 권장되지 않습니다.
무인자로 사용할 경우 형변환 하는 과정에서 의도되지 않게 삽입된 다른 객체들로 인해서 피해를 줄 수 있습니다.
제가 저 예제코드에서 String을 사용 목적으로 제네릭을 작성했는데, Date 같은 객체가 들어오면
내부 과정 중 ClassCastException 등 에러를 뿜게 될 것 입니다.
무인자로 작성했기에 잘못된 객체가 들어갈 수 있었기 때문입니다.
때문에 구체적 형 정보를 넘겨 컴파일러의 체크를 받게 하는 것이 안전합니다.
여기서 무인자는 사용하지 말아야 하지만, 아무 객체나 넣을 수 있는 Object를 형으로 주는 것인 괜찮습니다.
이 코드는 컴파일이 됩니다.
list가 무인자이기 때문에 경고를 주지만 컴파일이 되어서 나중에 에러를 띄울 수 있습니다.
하지만 Object를 제네릭 형으로 줘서 컴파일러에게 구체적인 정보를 줌으로써
훗날 생길 에러를 미연에 수정할 수 있게끔 도와줍니다.
제네릭을 많이 사용하는 컬렉션 계열 메소드를 사용할 때도 무인자는 지양해야합니다.
static int numElementsInCommon(Set s1, Set s2) {
int result = 0;
for (Object o1 : s1)
if (s2.contains(o1))
result++;
return result;
}
이런식의 Set 설정은 아무 객체나 넣을 수 있어서, 컬렉션의 자료형 불변식이 깨지기 쉽습니다.
때문에
static int numElementsInCommon(Set<?> s1, Set<?> s2)
비한정적 와일드카드 자료형(unbounded wildcard type)을 주어서
안정성과 유연석을 만족시켜주어야 합니다.
하지만 무인자를 써야하는 예외적인 상황도 있습니다.
먼저 클래스 리터럴에는 무인자를 사용해야합니다.
List.class, String[].class, int.class 등 자바 표준상 클래스 리터럴에는 형인자 자료형을 사용할 수 없습니다.
변화하지 않는 리터럴의 성격을 생각해보면 납득이 가지요.
두번째는 instanceof 연산자 사용 규칙에 관한 것입니다.
제네릭의 자료형 정보는 프로그램 시작과 동시에 지워집니다.
때문에 이런식으로
if(o instanceof Set) {
Set<?> m = (Set<?>) o;
}
Set의 클래스 정보만 체크하고, 나중에 형변환을 시켜주는 것이 좋습니다.
'프로그래밍 > Java' 카테고리의 다른 글
이펙티브 자바 규칙 24 - 무점검 경고를 제거하라 (0) | 2018.03.09 |
---|---|
이펙티브 자바 규칙 22 - 내부클래스 종류와 멤버 클래스는 가능하면 static으로 (0) | 2018.03.05 |
이펙티브 자바 규칙 21 - 전략을 표현하고 싶을 때는 함수 객체를 사용해라 (0) | 2018.02.21 |