제네릭 클래스(제네릭 인터페이스) : 클래스와 인터페이스 선언에 타입 매개변수가 쓰이는 것을 말함
ex) List 는 List라고 쓰기도 한다
→ 이를 통틀어서 제네릭 타입이라고 한다
제네릭의 매개변수화 타입 → List 원소의 타입이 String인 리스트를 뜻함
제네릭 타입을 정의 하면 그에 딸린 raw type 도 함께 정의된다
raw 타입 : 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않은 때를 말함
//raw 타입 -> 불안전
private final Collection stamps =
//매개변수화된 컬렉션 타입 -> 안전성 확보
private final Collection<Stamp> stamps =
raw 타입으로 정의 하면 잘못된 타입의 객체를 넣었을시 해당 객체 호출 때 까지는 모름
→ 런타임에 문제 발생!!
반면 매개변수회된 컬렉션 타입은 컴파일시 오류발생하여 확인 가능
비한정적 와일드 타입 <?>
어떤 타입이라도 담을 수 있는 범용적 매개변수화 타입이다→ 제네릭 타입을 쓰고 싶지만 실제 타입 매개변수가 무엇인지 신경쓰지 않고 싶을 때 사용
static int numElementsInCommon(set<?> s1, set<?>s2)
raw 타입으로 써야하는 경우
클래스 리터럴에는 로타입으로 써야 한다
List.class, String[].class (o)
List<String>.class, List<?>.class (x)
if (o instanceof Set){ //로타입
Set<?> s = (Set<?>) o //와일드카드 타입
제네릭 용어 정리
경고를 없엔다는 것 == 타입안정성을 확보하는것!
경고를 없엘 수 없지만 타입안전이 확실하다면
@Suppress Warings(”uncheked”)
를 달아 경고를 없에자
배열과 제네릭 타입의 차이
배열은 공변이다(공변 = 함께 변한다), 그러나 제네릭은 불공빈이다
배열은 실체화가 된다
List<String>[] stringLists = new List<String>[]
이런게 안된다는 뜻이다!
제네릭 배열 생성 오류를 해결하는 방법
제네릭 배열 생성을 금지하는 제약을 우회함
@SuppressWarings("unchecked")
public Stack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
elements 필드의 타입을 E[] → Object[]로 바꿈
public E Pop() {
if (size == 0)
throw new EMtpyStackException();
@SuppressWarnigs("unchekd")
E result = (E) elemets[--size];
elemtns[size] = null;
return result;
}
제네릭 메서드
public static <E> Set<E> union(Set<E> s1, Set<E> s2> {
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}
제네릭 싱글턴 팩터 : 타입 매개변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩터러
private static UnaryOperator<Object> IDENTITY_FN = (t) -> t;
@SUppressWarnings("unchecked")
public static <T> UnaryOperator<T> identityFunction() {
return (UnaryOperator<T>) IDENTITY_FN;
}
항등함수란 입력값을 수정없이 그대로 반환하는 특별함수이다
따라서 T가 어떤 타입이든 UnaryOperator를 사용해도 타입 안전하다
재귀적 한정 : 자기 자신이 들어간 표현식을 사용하여 타입 매개변수 허용범위를 한정할 수 있다.
public interface Comparalbe<T> {
int compareTo(T o);
}
여기서 매개면수 T는 Comparable를 구현한 타입이 비교할 수 있는 원소의 타입을 정의함
다음은 재귀적 타입한정을 이용해 상호 비교할 수 있음을 표현하는 코드
public static <E extends Comparable<E>> E max(Collection<E> c);
<E extends Comparable<E>> 는 모든 타입 E는 자신과 비교할 수 있다 라는 뜻
와일드 카드 공식
매개변수화 타입 T가
생산자일 경우
<? extends T>
//예시
public void pushAll(Iterable<? extends E> src {
for (E e : src)
push(e);
}
소비자라면
<? super T>
//예시
public void popAll(Collection<? super E> dst {
while (!isEmtpy())
dst.add(pop());
}
이를 갯풋 원칙이라고 부른다
매개변수 : 메서드 선언에 정의한 변수
인자 : 메서드 호출시 넘기는 실제값
void add(int value)
add(10)
value : 매개변수
10 : 인자
이를 제네릭으로 확장하면
class set<T>
Set<Integer>
제네릭 배열 매개변수에 값을 저장하는 것은 안전하지 않다
@SafeVarargs는 메서드 작성자가 그 메서드가 타입 안전함을 보장하는 장치이다.
타입 안전 이종 컨테이너 패턴 : 컨테이너 대신 키를 매개변수환 후 컨테이너에 값을 넣거나 뺼 때 매개변수화한 키를 함께 제공함 → 제네릭 타입 시스템이 값의 타입이 키와 같음을 보장
타입 안전 이종 컨테이너 패턴 API
public class Favorites {
public <T> void putFavorite(Calss<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
타입 안전 이종 컨테이너 패턴 - 클라이언트
public static void main(String[] args){
Favorites f = new Favorites();
f.putFavorite(String.class, "JAVA");
String favoriteString = f.getFavorite(String.class);
System.out.printf("%s", favoriteString);
}