💡 제네릭(Generic) : 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다. 한마디로 특정(Specific) 타입을 미리 지정해주는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반(Generic) 타입이라는 뜻
제네리은 java5부터 추가 되었다.
이전에는 컬렉션에서 객체를 읽어서 캐스트 해야함 -> 이 때 런타입 캐스트 에러가 발생할 위험이 있다.
Example<T>
Example<String>
<T>
Example<E>
Example<String>
Example
로타입은 제네릭 전 후 코드의 호환을 위한 것이며, 동작하지만 좋은 예는 아님!import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class RawType {
public static void main(String[] args) {
List onlyString = new ArrayList();
onlyString.add("문자열1");
onlyString.add("문자열2");
onlyString.add(13579);
for (Iterator i = onlyString.iterator(); i.hasNext(); ) {
String s = (String) i.next(); // ClassCastException 을 던진다.
}
}
}
실제로 값을 가져와서 캐스팅을 하는 시점에 오류가 발생하기 때문에, 컴파일러는 ClassCastException
을 던진다.
컴파일 전엔 아무런 에러가 발생하지 않는다!!
import java.util.ArrayList;
import java.util.List;
public class GernericType {
public static void main(String[] args) {
List<String> onlyString2 = new ArrayList<String>();
onlyString2.add("string1");
onlyString2.add("string2");
onlyString2.add(13579);
}
}
컴파일 전 부터 에러가 난다!
로타입을 사용을 절대로 하지 말아야하는 이유는 하위버전과의 호환성 때문이다.!!
컬렉션의 타입 파라미터를 모르거나 어떤 원소 타입이던 넣고 사용하고 싶다면 비한정적 와일드 카드 타입 을 사용해라!
<E>
-> <?>
null
을 제외한 그 어떤 타입의 인스턴스도 넣을 수 없다. 즉, 컬렉션의 타입 불변식을 훼손하지 못하도록 아예 막아버림
그래서 로타입보다 훨씬 안전!
이 제약에서 벗어나고 싶으면 ? extends 클래스
와 같이 한정적 와일드 카드 타입을 이용해 어떤 클래스의 하위 클래스를 받을 것인지 명시하면 된다.
class
리터럴을 사용할 때class
리터럴에 매개변수화 타입을 사용하지 못하게 하였다. (배열과 기본 타입 허용)List.class
, String[].class
, int.class
는 허용하고, List<String>.class
와 List<?>.class
는 허용하지 않는다.instanceof
연산자를 사용할 때instanceof
연산자는 비 한정적 와일드 카드 타입 이외의 매개변수화 타입에는 적용할 수 없다.instanceof
는 완전 똑같이 동작한다.