다양한 데이터 타입을 처리할 수 있는 클래스, 인터페이스, 메서드를 작성하는 기법이다.

클래스(또는 인터페이스) 정의에 타입 매개변수를 넣는 방식으로 해당 클래스 전체 범위에서 타입을 사용할 수 있다.
java
class Holder<T> {
private T data;
public Holder(T data) {
this.data = data;
}
public T get() { return data; }
public void set(T data) { this.data = data; }
}

제네릭 클래스의 선언
<>에 타입 파라미터를 표시한다.관례적으로 자주 쓰는 이름
T: TypeE: ElementK: KeyV: Value
제네릭 클래스의 객체 생성
변수 선언 쪽과 생성자 쪽의 타입은 반드시 일치해야 한다.
Holder<String> h1 = new Holder<String>("hello");
System.out.println(h1.get()); // hello
타입이 추론 가능한 경우, 생성자 쪽 타입은 생략할 수 있다. (Java 7+ 다이아몬드 연산자 <>)
Holder<Integer> h2 = new Holder<>(100);
System.out.println(h2.get()); // 100
제네릭 타입을 지정하지 않는 raw type으로도 생성할 수 있지만 권장하지 않는다.
→ 타입 안정성이 깨지고, 타입 파라미터 T가 사실상 Object처럼 취급된다.
제네릭 메서드는 메서드 내부에서 사용할 타입 파라미터를 메서드가 직접 선언하는 방식이다.
즉, 클래스에 제네릭이 있든 없든 상관없이, 특정 메서드만 제네릭하게 만들 수 있다.
public static <T> T methodName(...)클래스명.<타입>메서드명(...) String s = Utils.<String>first("A", "B");
Integer n = Utils.<Integer>first(1, 2);
한정된 타입 매개변수는 제네릭을 정의할 때, 아무 타입이나 다 받는 것이 아니라 특정 범위의 타입만 허용하고 싶을 때 사용한다.
extends 키워드를 사용한다. extends는 상속뿐 아니라 인터페이스 제한에도 사용된다.super(하한 경계)는 와일드카드에서 사용한다.
| 종류 | 표현 | 설명 |
|---|---|---|
| 제한없는 와일드 카드 | GenericType<?> |
타입에 제한이 없음 |
| 상한 경계 와일드 카드 | GenericType<? extends T> |
T와 T를 상속받은 타입만 사용 가능 |
| 하한 경계 와일드 카드 | GenericType<? super T> |
T와 T의 조상 타입만 사용 가능 |

제네릭 끝.!