Java 제네릭(Generic) 이란 무엇인가?
자바8의 함수형 인터페이스를 보면 인자와 리턴 타입이 제네릭으로 지정되어 있는것을 볼 수 있습니다.
개인적으로 제네릭은 어렵다고 느끼고 있었는데, 그래서 더욱 개념을 명확히 잡는게 중요하다고 생각합니다.
그래서 이렇게 제네릭(Generic)이 무엇인지 알아보려고 합니다.
살펴볼 내용입니다.
제네릭과제네릭을 사용해야 하는 이유
제네릭 타입
제네릭 메소드
타입의 제한
와일드 카드 타입
1. 제네릭이란 ?
다양한 타입의 객체에 재사용을 높일 수 있는 기법으로 클래스에서 사용할 타입을
외부에서 설정하는 것을 말합니다.
선언 시 클래스 또는 인터페이스 에 "<>" 를 붙이고 타입파라미터를 지정합니다.
제네릭을 사용하지 않을 경우 빈번한 타입 변환이 발생 할 수 있으며 이는 프로그램의 성능을 저하시킵니다.
아래의 예시를 살펴볼까요?
Object 타입을 사용하여 클래스를 생성하였습니다.
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. 제네릭타입
메소드 내부에서 사용할 타입을 외부에서 인자로 받을 건데요. 인스턴스를 생성하는 시점 또는 메소드를 호출하는 시점에
정할 수 있습니다. 이제 적용해 보겠습니다.
public class Car<T> {
private T t;
public void set(T t) {this.t = t;}
public T get() {return t;}
}
먼저 Object 를 T로 바꿨고 해당 클래스에서 사용하는 T 라고 정의하고 인스턴스 생성시 받아서 정한다는 의미입니다.
그리고 이렇게 사용합니다.
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();
클래스를 선언할 때 타입 파라미터를 사용하여 컴파일 시 타입 파라미터가 구체적인 클래스로 변경됩니다.
멀티 타입의 파라미터도 사용이 가능합니다.
제네릭 타입은 두개 이상의 타입 파라미터를 사용가능한데요
- 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();
class Car<T extends String, M extends Number>
타입 인자 |
의미 |
E |
Element |
K |
Key |
N |
Number |
T |
Type |
V |
Value |
R |
Result |
3. 제네릭 메소드
제네릭 메소드는 매개변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메소르를 말합니다.
일반적으로 제네릭 클래스를 사용할 떄와 비슷합니다.
다만, 리턴 타입 앞에 타입 파라미터를 넣어야 하고 이 타입 파라미터는 리턴 타입과 매개변수에 사용됩니다.
먼저 제네릭 클래스를 만듭니다.
public class Car<T, M> {
private T color;
private M model;
public Car(T color, M model) {
this.color = color;
this.model = 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;}
}
제네릭 메소드를 선언합니다.
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);
4. 타입의 제한
타입 파라미터에 지정되는 타입이 제한할 필요가 있습니다.
제네릭 메소드에서도 타입을 제한 할 수 있습니다.
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){...}
상위 타입은 클래스와 인터페이스도 가능합니다.
5. 와일드 카드 타입
와일드카드 타입에는 세가지의 형태가 있습니다.
? 키워드로 표시됩니다.
먼저 제네릭타입<?> 입니다.
타입 파라미터를 대치 하는 것으로 모든 클래스나 인터페이스 타입이 올 수 있습니다.
public static boolean compare(Car<?> c1, Car<?> c2) {
boolean colorCompare = c1.getcolor().equals(c2.getcolor()) ;
return colorCompare;
}
제네릭타입<? extends 상위타입>
와일드카드의 범위를 특정 객체의 하위로 제한하는 것입니다.
public static boolean compare(Car<? extends String> c1, Car<? extends String> c2) {
boolean colorCompare = c1.getcolor().equals(c2.getcolor()) ;
return colorCompare;
}
제네릭타입<? super 하위타입>
위의 반대로 상위클래스만 올 수 있게 합니다.
public static boolean compare(Car<? super String> c1, Car<? super String> c2) {
boolean colorCompare = c1.getcolor().equals(c2.getcolor()) ;
return colorCompare;
}
이렇게 제한을 둘 경우 단지 클래스의 제한이 아닌 예상치 못한 에러를 컴파일 단계에서부터 찾아낼 수 있습니다.
그리고 인터페이스도 제네릭으로 구현 할 수 있습니다.
제네릭 인터페이스를 구현한 클래스 또한 제네릭 타입으로 구현해야 한다점을 기억해야 합니다.
이렇게 자바 제네릭의 개념에 대해 살펴보았습니다.
도움이 되셨다면 공감♥을 눌러주세요.
참고 : 이것이 자바다