"어렵고 어려운 제네릭".... 에 대해 다뤄본다.
제네릭-상 에 이어지는 글입니다.
매개타입과 리턴 타입으로 타입파라미터를 갖는 메소드를 말한다.
public <타입파라미터, ..> 리턴타입 메소드명(매개변수, ...) {
}
코드처럼 타입 앞에 <> 를 추가하고 타입 파라미터를 기술한다음, 리턴 타입, 매개 타입으로 타입 파라미터를 사용하면 된다.
public <T> Box<T> boxing(T t) {
}
Box<Integer> box = boxing(100);
boxing을 선언한 부분에서는 T 타입으로 선언을 하고, 사용시 Integer를 명시해줌으로써 정수를 함수 내에 넣게 된다.
타입 파라미터에 구체적인 타입을 제한하는 기능
예를 들어, 숫자를 연산하는 제네릭 메소드가 존재할때, 숫자형식의 타입 인스턴스만 가질 수 있게 제한하는 방법이다.
public **<T extends 상위타입>** 리턴타입 메소드(매개변수, ...) {
}
public <T extends Number> int compare(T t1, T t2) {
double v1 = t1.doubleValue();
double v2 = t2.doubleValue();
return Double.compare(v1, v2)
}
<T extends Number>
이 부분에 집중해 보자 !
T라는 타입 파라미터를 사용하지만 extends Numbers라는 부분을 통해 Number타입이나 Byte, Short, Integer, Long, Double 같은 Numbers를 상속받은 인스턴스만 사용 가능하게 된다.
코드에서 ? 기호를 일반적으로 와일드카드라고 부른다.
보통 제한을 두고 싶지 않을때? 많이 사용하는 기호이다.
제네릭 타입을 매개값이나 리턴 타입으로 사용할때, 구체적인 타입 대신 와일드 카드를 사용한다.
아래와 같이 3가지 형태로 사용한다.
제네릭타입 <?> : Unbounded Wildcards (제한 없음)
제네릭 타입 <? extends 상위타입> : Upper Bounded Wildcards (상위 클래스 제한)
제네릭 타입 <? super 하위타입> : Lower Bounded Wildcards (하위 클래스 제한)
다음과 같은 관계로 클래스가 존재한다고 가정해보자.
위 3가지 형태를 해당 예시에 적용하면 다음과 같다.
Course<?>
: 수강생은 모든 타입(Person, Worker, Student, HighStudent)이 될 수 있다.Course<? extends Student>
: 수강생은 Student와 HighStudent만 될 수 있다.Course<? super Worker>
: 수강생은 Worker와 Person만 될 수 있다.제네릭 타입 역시 상속이 가능하다.
public class ChildProduct<T, M> extends Product<T, M> {
}
위 코드는 Product<T, M> 을 상속받은 ChildProduct<T, M>을 보여준다.
제네릭타입의 상속의 경우 특징이 한 가지 존재한다.
자식 제네릭 타입은 추가적으로 타입 파라미터를 가질 수 있다.
public class ChildProduct<T, M, C> extends Product<T, M> {
}
부모에게 상속 받은 T, M 뿐 아니라 위와 같이 새로운 타입 파라미터를 추가할 수 있다.
만약 제네릭 인터페이스를 구현한 클래스가 있다고 가정하자.
해당 클래스는 무조건 제네릭 타입이여야 한다.
public interface Storage<T> {
void add(T item, int index);
T get(int index);
}
위와 같이 Stroage라는 제네릭 인터페이스가 있다.
public class StorageImpl<T> implements Storage<T> {
private T[] array;
public StorageImpl(int capacity) {
array = (T[]) (new Object[capacity]);
}
@Override
public void add(T item, int index) {
array[index] = item;
}
@Override
public T get(int index) {
return array[index];
}
}
그렇다면, Storage를 구현한 StorageImpl 클래스도 위와 같이 제네릭 타입이여야한다.
자바 심화부분 특히 최근 자바에 추가된 내용들이 나오면서 (+스트림, 람다) 새롭게 공부해야할 내용들이 많아지는 느낌이다. 새롭게 추가되었다고 무조건적으로 좋은 기술들은 아니기에 장점은 극대화하고 단점은 최소화하며 내 코드에 녹이는 연습이 필요하다. 😏
코드 예시 출처 : 이스트소프트 부트캠프 - 오르미