Generic
Generic
제네릭(Generic): 타입을 매개변수화(parameterize)하는 기능. 클래스나 메서드가 사용할 타입을 외부(사용 시점)에서 결정할 수 있게 한다.
개념
<>를 사용한 클래스를 제네릭 클래스라고 한다.<>기호를 다이아몬드 연산자(Diamond Operator)라고 한다.- 제네릭은 타입을 매개변수화(parameterize)하는 기능이다.
즉, 클래스나 메서드가 사용할 타입을 외부에서 결정할 수 있게 한다.
제네릭을 사용하는 이유
- 타입 안전성 (Type Safety) | 구분 | 오류 발생 | | ------ | ----- | | 제네릭 없음 | 런타임 | | 제네릭 있음 | 컴파일 |
- 캐스팅 제거
타입 매개변수 선언
| 위치 | 의미 | | --------- | ---------- | |<T> | 타입 매개변수 선언 |
| T value | 실제 타입 사용 |
사용 예시
제네릭 명명 관례
| 타입 | 의미 |
|---|---|
| T | Type |
| E | Element |
| K | Key |
| V | Value |
| N | Number |
| S,U,V | 여러 타입 |
여러 타입 매개변수
제네릭 타입 제한 (Bounded Type)
- 특정 타입만 허용한다.
다중 상한 (Multiple Bounds)
- 클래스 1개 + 인터페이스 여러개
규칙
- 클래스는 1개만 가능
- 클래스는 맨 앞
- 이후는 인터페이스
Generic Method
- 메서드 자체가 제네릭이 될 수 있다.
Instance / Static Generic Method
Class Generic vs Method Generic
우선순위
- 메서드 제네릭이 클래스 제네릭보다 우선
- 여기서 T 는 메서드 타입
Raw Type
- 제네릭을 사용하지 않는 타입
문제
- 타입 안정성 깨짐
- 캐스팅 필요
- 컴파일 경고
Wildcard
- 제네릭 타입을 사용할 때 타입 범위를 표현
주의
- 제네릭 선언이 아님
- 사용 시점 타입 표현
비제한 wildcard
상한 wildcard
하한 wildcard
PECS 원칙 (매우 중요)
- 제네릭 설계 핵심 원칙 | 역할 | 사용 | | ---------- | ------- | | 데이터를 꺼내는 곳 | extends | | 데이터를 넣는 곳 | super |
예시
public static double sum(List<? extends Number> list)
=> 데이터를 꺼낼 수 있지만, 어떤 리스트인지 몰라 넣을 수 없음
public static void add(List<? super Integer> list)
=> 데이터를 넣을 수 있지만, 꺼낼 때 어떤 리스트인지 몰라 꺼낼 수 없음
제네릭 불공변성 (Invariance)
- Java 제네릭은 불공변
Generic 배열 생성 제한
Type Erasure (타입 소거)
- 자바 제네릭은 컴파일 이후 제거된다.
Type Erasure 과정
=> 시작
class Box<T> {
T value;
}
=> 컴파일 후
class Box {
Object value;
}
=> 제한이 있으면
class Box<T extends Number>
=> 컴파일 후
class Box {
Number value;
}
Type Erasure 때문에 불가능한 것
제네릭 핵심
목적
- 타입 안정성
- 캐스팅 제거
- 코드 재사용
특징
- 컴파일 타입 체크
- 타입 소거 기반
- 불공변
- 와일드카드 사용