제네릭
제네릭이란?
- 프로그램에서 변수를 선언할 때 모든 변수는 자료형이 있다.
- 메소드에서 인자를 사용할 때도 자료형을 갖고 있따.
- 변수나 메소드의 자료형을 필요에 따라 여러 자료형으로 바꿀 수 있다면 프로그램이 훨씬 유연할 것이다.
- 어떤 갑싱 하나의 참조 자료형이 아닌 여러 참조 자료형을 사용할 수 있도록 프로그래밍 하는 것을 Generic programming 이라고 한다
- Generic 프로그램은 reference 자료형에 대한 검증을 컴파일러가 해 안정적이다.
- Collection 역시 generic으로 구현되어있다 (ex
ArrayList<String>
)
제네릭의 정의
public class GenericPrinter<T> {
private T material;
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() {
return material;
}
}
- 여러 자료형으로 바꿔 사용할
material
변수의 자료형을 T라고 지정했다. 이때의 T를 type parameter라고 부른다. - 클래스 이름을
GenericPrinter<T>
라고 정의하고 나중에 클래스를 사용할때 T위치에 실제 사용할 자료형을 지정한다.
다이아몬드 연산자
- 자바 7부터는 제네릭 자료형의 클래스를 생성할 때 생성자에 사용하는 자료형을 명시하지 않을 수 있다.
ArrayList<String> list = new ArrayList<>();
자료형 매개변수 T와 static
- static 변수나 메소드는 인스턴스 생성 여부와 상관 없이 클래스 이름으로 호출할 수 있다.
- 그런데 T의 자료형이 정해지는 순간은 generic 클래스의 인스턴스가 생성되는 순간이다. 따라서 T의 자료형이 결정되는 시점보다 빠르기 때문에 static변수의 자료형이나 메소드 내부 변수의 자료형으로 T 키워드를 사용할 수 없다.
제네릭 테스트
- generic을 사용할 나머지 클래스를 만든다.
public class ABS {
public void doPrinting() {
System.out.printf("Using ABS");
}
public String toString() {
return "Material is ABS.";
}
}
public class PBT {
public void doPrinting() {
System.out.printf("Using PBT");
}
public String toString() {
return "Material is PBT.";
}
}
public class GenericPrinterTest {
public static void main(String[] args) {
GenericPrinter<ABS> absPrinter = new GenericPrinter<>();
absPrinter.setMaterial(new ABS());
ABS abs = absPrinter.getMaterial();
System.out.println(absPrinter);
GenericPrinter<PBT> pbtPrinter = new GenericPrinter<>();
pbtPrinter.setMaterial(new PBT());
PBT pbt = pbtPrinter.getMaterial();
System.out.println(pbtPrinter);
}
}
- 아래는 실행결과다
Material is ABS.
Material is PBT.
T 자료형에 사용할 자료형을 제한하는 <T extends Class>
- 제네릭 클래스에서 T에 사용할 자료형을 제한할 수 있다.
- abstract 클래스의 extends를 통해 구현한다.
public abstract class Material {
public abstract void doPrinting();
}
추상클래스에 대해 상속(extends)을 받는다.
public class ABS extends Material {
public void doPrinting() {
...
public class ABS extends Material {
public void doPrinting() {
...
- 그리고 제네릭 클래스에 다음과 같이 추가한다
public class GenericPrinter<T extends Material> {
private T material;
...
- 이렇게 하면
Material
을 상속(extends)받는 클래스만이 제네릭을 사용할 수 있게 된다.