자바의 제네릭에 대해 학습하세요.
제네릭 타입은 클래스와 메서드에 사용할 수 있다. 선언시 클래스 또는 메서드 뒤에 <>
이 붙고 <>
사이에는 타입 파라미터가 위치한다.
public class NonGenericsClass {
Object item;
void setItem(Object item) {
this.item = item;
}
Object getItem() {
return item;
}
}
public class GenericsClass<T> {
T item;
void setItem(T item) {
this.item = item;
}
T getItem() {
return item;
}
}
public class GenericsClass<T> {
...
public static void main(String[] args) {
GenericsClass<Integer> integerGenerics = new GenericsClass<>();
integerGenerics.setItem(3);
Integer item = integerGenerics.getItem();
System.out.println(item);
GenericsClass<String> stringGenerics = new GenericsClass<>();
stringGenerics.setItem("hi");
String item = stringGenerics.getItem();
System.out.println(item);
}
}
타입 파라미터에 Integer, String을 넣어봤다. 컴파일 시 클래스 타입이 달라지는 것을 확인할 수 있다.
제네릭으로 사용되는 파라미터 타입을 제한할 수 있는 것을 말한다.
예를 들어 숫자를 연산하는 제네릭 메소에는 Number타입과 그 하위 타입의 인스턴스만 가져야 한다. 이것이 바운디드 타입이 필요한 이유다.
바운디드 타입은 extends 키워드를 붙이고 상위 타입을 명시하면 되는데 이 때 extends는 상속이 아닌 종류의 의미로 사용된다.
public <T extends 상위타입> 리턴타입 메소드명(매개변수, ...) {
...
}
일반적으로 코드에서의 ?를 와일드카드라고 부른다. 제네릭 타입을 매개변수나 리턴타입으로 사용할 때 바운디드 타입과 마찬가지로 타입 파라미터를 제한할 목적으로 사용된다.
와일드 카드를 사용하는 경우는 상위, 하위 타입으로의 변환이 가능한 것을 제한하기 위함이다.
제네릭타입<?> : 제한 없음
제네릭타입<? extends 상위타입> : UpperBounded WildCards
제네릭타입<? super 하위타입> : LowerBounded WildCards
매개변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메서드를 말한다.
<>
를 추가하고 타입 파라미터를 기술한다.public <타입 파라미터> 리턴타입 메소드명(매개변수, ...) {
...
}
참조
제네릭은 제네릭 도입 전 코드와의 호환성 유지를 위한 작업을 동시에 진행했다. 따라서 코드의 호환성을 위해 erasure 방식을 사용한다.
제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 Raw type이라고 한다. Raw type을 사용하는 것
erasure 방식은 컴파일 타입에만 타입 제약 조건을 정의하고, 런타임에서는 타입을 제거한다.
public class Example<T> {
public void method(T type) {
System.out.println(type.toString());
}
}
public class Example {
public void method(Object type) {
System.out.println(type.toString());
}
}
위처럼 unbounded type에서는 Object로 바뀌게 된다.
그럼 bounded type은 어떻게 바뀔까?
public class Example<T extends Comparable<T>> {
public void method(T type) {
System.out.println(type.toString());
}
}
public class Example {
public void method(Comparable type) {
System.out.println(type.toString());
}
}
<T extends Comparable>와 같이 제한된 제네릭을 걸어두면 제한시킨 타입인 Comparable 타입으로 변환이 된다.