자바로 개발 하다 보면 < ? > 형식의 코드들이 보인다.
나는 제네릭에 대해 공부하지 못하여 이게 뭔지 궁금했다.
그래서 자세히 알아보려 한다!
1. 제네릭(Generic)
다양한 타입의 객체에 재사용을 높일 수 있는 기법으로 클래스에서 사용할 타입을 외부에서 설정하는 것을 말한다.
선언 시 클래스 또는 인터페이스에 "<>"를 붙이고 타입 파라미터를 지정한다.
제네릭을 사용하지 않을 경우 빈번한 타입 변환이 발생 할 수 있으며 이는 프로그램 성능을 저하시킨다.
예시를 보자!
public class Car{
private Object obj;
public void set(Object obj){
this.obj = obj;
}
public Object get(){
return obj;
}
Car car = new Car();
car.set("Black");
String color = (String)car.get();
Object타입으로 선언 하였기 때문에 사용할 때 String 타입으로 강제로 타입을 변환해줘야 한다.
또한 잘못된 타입이 사용될 수 있는 문제가 발생 할 수도 있다.
그래서 제네릭을 사용하면 컴파일 시에 타입 체크가 가능하고, 실행 시 타입 에러가 나는 것을 방지 할 수 있다.
2. 제네릭 타입 (Generic Type)
제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다. 제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 "<>" 부호가 붙고, 사이에 타입 파라미터가 위치합니다.
public class Car <T>{
private T object;
public void setObj( T obj ) {
this.object = obj;
}
public T getObj() {
return object;
}
}
Car<String> car1 = new Car<String>();
car1.set("Black");
String color = car1.get();
Car<Integer> car2 = new Car<Integer>();
car2.set(3);
int colornum = car2.get();
3. 멀티 타입 파라미터
제네릭 타입은 두 개 이상의 파라메터를 클라이언트 측에서 받아오고 싶을 때 < A , B , …> 처럼 사용할 수 있다.
- class<K, V, …> { … }
- interface<K, V, …> { … }
이러한 형식으로 사용이 가능하다.
public class Car<T, M> {
private T color;
private M model;
public void setcolor(T color) {
this.color =color;
}
public void setmodel(M model) {
this.model = model;
}
public T getcolor() {
return color;
}
public M getmodel() {
return model;
}
}
Car<String, String> car = new Car<String, String>();
car.setcolor("Black");
car.setmodel("SUV");
String color = car.getcolor();
4. 제한된 타입 파라미터
제네릭의 상위 타입을 구체적으로 제한하고 싶을 경우가 있다. 메서드, 인터페이스, 클래스에서 동일하게 사용 가능하며 < T extends 상위타입>으로 제한할 수 있다. 예를 들어 내부에서 사용할 T 객체가 꼭 Number 클래스의 하위 타입이어야 할 때, 혹은 원하는 상위 인터페이스의 구현체이어야 할 때 사용 가능하다. 그래야 메소드 안에서 필요한 인터페스의 메소드 혹은 클래스의 메소드를 사용할 수 있다.
타입 파라미터에 지정되는 타입이 제한할 필요가 있다.
제네릭 메소드에서도 타입을 제한 할 수 있다.
public static <T extends String, V extends String> boolean compare(Car<T, V> c1, Car<T, V> c2){...}
public static <T extends String, V extends Number> boolean compare(Car<T, V> c1, Car<T, V> c2){...}
상위 타입은 클래스와 인터페이스도 가능하다.
보통 자주 사용하는 타입 인자
타입 인자 | 의미 |
E | Element |
K | Key |
N | Number |
T | Type |
V | Value |
R | Result |
5. 제네릭 메서드
제네릭 메소드는 매개타입 또는 리턴타입으로 타입파라메터를 갖는 메소드를 말한다. 선언하는 방법은 리턴타입 앞에 <>를 추가하고 적어준다. 즉, 메소드에서 사용할 부분을 리턴타입 내부 <>에 적어주고 뒤에서 사용하면 된다.
public class genericSample {
public static <T, V> boolean compare(Car<T, V> c1, Car<T, V> c2) {
boolean colorCompare = c1.getcolor().equals(c2.getcolor()) ;
boolean modelCompare = c1.getmodel().equals(c2.getmodel());
return colorCompare && modelCompare;
}
}
제네릭 메소드를 호출하는 방법이다.
명시적으로 지정할 수 도 있고 매개 값을 보고 타입을 추정 할 수 있다.
Car<String, String> c1 = new Car<String, String>("black", "SUV"); //타입 파라미터를 명시적으로 지정
Car<String, String> c2 = new Car("black", "SUV"); //타입 파라미터를 String 으로 추정
boolean result1 = genericSample.<String, String>compare(c1, c2);
6. 와일드카드 타입
코드에서 ?를 일반적으로 와일드카드라고 부른다. 사용하는 경우는 아래와 같다.
<?>
모든 클래스나 인터페이스가 올 수 있습니다. 즉 제한없음. A ~ E 모두 올 수 있다.
<? extends 상위타입>
상위타입 이하로만 올 수 있습니다. <? extends D> => D, E 가능
<? supper 하위타입>
하위타입 이상으로만 올 수 있습니다. <? supper D> => D, A 가능
제네릭에 대해 정리해 보았다.
정리해서 보는것 보다 실제 적용을 해보고 온전한 내것으로 만들어야겠다!!
🎈참고 사이트🎈