제네릭(Generic)
클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미
데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법
장점
- 제네릭을 사용하면 잘못된 타입이 들어올 수 있는 것을 캄파일 단계에서 방지 가능
(타입 안정성을 높이고, 형변환의 번거로움이 줄어듬 -> 코드 간결 )- 클래스 외부에서 타입을 지정하기 때문에 타입을 체크하고, 변환해줄 필요 X
- 비슷한 기능을 지원하는 경우, 코드의 재사용성 높아짐
<T> Type
<E> Element
<K> Key
<V> Value
<N> Number
클래스 및 인터페이스
public class 클래스명 <T> { ... } public Interface 인터페이스명 <T> { ...}
클래스명 - 원시 타입(raw type)
T - 타입 변수(type variable) 또는 타입 매개변수(T : 타입 문자)
- T뿐만 아니라 어떠한 문자를 사용해도 상관없고, 여러 개의 타입 변수는 쉼표(,)를 구분하여 명시 가능
- 타입 변수는 클래스에서뿐만 아니라 메서드의 매개변수나 반환값으로도 사용할 수 있음
자바에서 타입 변수 자리에 사용할 실제 타입을 명시할 때는 wrapper 클래스를 사용해야함
클래스명 generic 클래스 'T의 클래스명' 또는 'T 클래스명'이라고 읽음
타입 문자 T는 generic 클래스의 타입 변수 또는 타입 매개변수라고 하는데, 메서드의 매개변수와 유사한 면이 있기 때문. -> 지네릭 타입 호출이라하고, 지정된 타입을 매개변수화된 타입(parameterized type)이라고 함
제네릭 타입 두개로 둘 수 있음(ex) HashMap)public class 클래스명 <T> { ... } public class Person { ... } public class Main{ public static void main(String[] args){ 클래스명<Person> p = new 클래스명<Person>(); // 사용자가 정의한 클래스도 타입으로 올 수 O } }
제네릭 메서드
제네릭 메서드란 메서드의 선언부에 타입 변수를 사용한 메서드를 의미
이때 타입 변수의 선언은 메서드 선언부에서 반환 타입 바로 앞에 위치
public void <T> void methodName(..) {...}
// 제네릭 클래스 class 클래스명<E>{ private E element; // 제네릭 변수 E get(){ // 제네릭 메서드 return element; } void set(E element){ // 제네릭 메서드 this.element = element; } } // 메인 클래스 class Main{ public static void main(String[] args) { 클래스명<String> str = new 클래스명<String>(); 클래스명<Integer> num = new 클래스명<Integer>(); str.set("1"); num.set(1); System.out.println("str data : " + str.get()); System.out.println("str E Type : " + str.get().getClass().getName()); // 반환된 변수 타입 System.out.println("num data : " + num.get()); System.out.println("num E Type : " + num.get().getClass().getName()); } }
출력 결과
str data : 1 str E Type : java.lang.String num data : 1 num E Type : java.lang.Integer
제네릭스의 제한
<? extends T>
T 와 같은 타입 변수를 사용하여 타입 제한
extends 키워드 -> 타입 변수에 특정 타입만을 사용하도록 제한할 수 있음
ex)<? extends A> // A타입만 올 수 있음 + 상속 <? extends Number> // 수를 표현하는 Wrapper 클래스만으로 제한 class AnimalList<T extends Animal> {...}
위와 같이 제한을 두면 클래스 내부에서 사용된 모든 타입 변수에 제한이 걸림
이때 클래스가 아닌 인터페이스를 구현할 경우에도implements가 아닌 extends 사용
ex)interface Fly{...} ... class AnimalList <T extends Run>{...}
클래스와 인터페이스를 동시에 상속&구현해야 한다면 & 기호 사용
<? super T>
T 타입의 조상 타입만 가능
<?> (와일드 카드) == <? extends Object>
어떤 타입이든 상관 X -> 보통 데이터가 아닌 기능의 사용 위주
generic의 제거 시기
자바 코드에서 선언되고 사용된 제네릭 타입은 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환된다. 그후, 코드 내의 모든 제네릭 타입은 제거되어, 컴파일된 class 파일에는 어떠한 제네릭 타입도 포함되지 않게 된다
(generic을 사용하지 않는 코드와의 호환성을 유지하기 위해)