[java] 제네릭(Generic) 프로그래밍
제네릭 자료형 정의
- 클래스에서 사용하는 변수의 자료형이 여러개 일 수 있고, 그 기능(메서드)은 동일한 경우 클래스의 자료형을 특정하지 않고 추후 해당 클래스를 사용할 때 지정할 수 있도록 선언
- 실제 사용되는 자료형의 변환은 컴파일러에 검증되므로 안정적인 프로그래밍 방식
- 컬렉션 프레임워크에서 많이 사용되고 있음
제네릭 타입을 사용하지 않는 경우의 예
예를 들어 3DPrinter의 재료가 바뀌는 경우이다.
Powder, Plastic, ThreeDPrinter1, ThreeDPrinter2, ThreeDPrinter3 총 5개의 클래스파일을 생성한다.
Powder.java
public class Powder {
public String toString() {
return "재료는 Powder입니다.";
}
}
Plastic.java
package org.example;
public class Plastic {
public String toString() {
return "재료는 Plastic입니다.";
}
}
ThreeDPrinter1.java
package org.example;
public class ThreeDPrinter1 {
private Powder material;
// private Plastic
public Powder getMaterial() {
return material;
}
public void setMaterial(Powder material) {
this.material = material;
}
}
ThreeDPrinter2.java
package org.example;
public class ThreeDPrinter2 {
private Plastic material;
// private Plastic
public Plastic getMaterial() {
return material;
}
public void setMaterial(Plastic material) {
this.material = material;
}
}
여기서 ThreeDPrinter1, 2의 클래스파일은 각각 Powder, Plastic을 재료로 한다.
이런 식으로 같은 행위를 하지만 재료만 다를 때, 여러 개의 클래스 파일을 생성하는 것을 비효율적이다.
그래서 Type의 최상위 객체인 Object type을 이용하여 프로그래밍 했었다. 예시는 아래와 같다.
- ThreeDPrinter3.java
package org.example;
public class ThreeDPrinter3 {
private Object material;
// private Plastic
public Object getMaterial() {
return material;
}
public void setMaterial(Object material) {
this.material = material;
}
}
하지만 이렇게 프로그래밍하게 된다면 한 가지 불편한 점이 생기는데, 그것은 바로
package org.example;
public class ThreeDPrinterTest {
public static void main(String[] args){
Powder powder = new Powder();
ThreeDPrinter3 printer3 = new ThreeDPrinter3();
printer3.setMaterial(powder);
Powder p = (Powder)printer3.getMaterial();
}
}
제일 아랫 줄에서
Powder p = (Powder)printer3.getMaterial();
이 줄이 문제가 된다. printer3 객체의 getMaterial() 메소드를 사용하여 Powder 타입의 p 객체를 불러오려 하지만, 타입이 맞지 않기 때문에 (Powder) 를 붙임으로써 형변환을 시켜주어야 에러가 뜨지 않는다. 그렇기 때문에 제네릭 프로그래밍을 사용한다.
- 제네릭 프로그래밍을 사용한 경우
- GenericPrinter.java
package org.example;
public class GenericPrinter<T> {
private T material;
public T getMaterial() {
return material;
}
public void setMaterial(T material) {
this.material = material;
}
public String toString(){
return material.toString();
}
}
위와 같이 클래스파일의 파일명 옆에 다이아몬드 연산자 <>와 그 안에 Type을 의미하는 T를 넣습니다.
그럼 제네릭을 사용할 수 있게 되며, 타입을 지정해주지 않아도 됩니다.
- ThreeDPrinterTest.java
package org.example;
public class ThreeDPrinterTest {
public static void main(String[] args){
Powder powder = new Powder();
ThreeDPrinter3 printer3 = new ThreeDPrinter3();
printer3.setMaterial(powder);
Powder p = (Powder)printer3.getMaterial();
System.out.println(p.toString());
}
}
출력 결과
재료는 Powder입니다.