[Back-End][Java] 39. 제네릭(Generic) 프로그래밍 (2)
제네릭 자료형 범위 제한하기
<T extends 클래스명> 으로 T 자료형의 범위를 제한할 수 있다.
제한하지 않으면, 자료형으로 아무 클래스나 올 수 있다.
Material.java
public abstract class Material {
// 추상 메서드
public abstract void doPrinting();
}
재료들의 상위 클래스로 Material 클래스를 생성해 준다.
new 해서 실제 메모리에 사용할 목적이 아닌 재료 클래스들을 묶어주고,
메소드 명은 같지만 각 클래스별로 재정의할 수 있도록 하기 위한 목적이니 추상클래스로 생성했다.
Plastic.java
public class Plastic extends Material {
// 추상메서드 재구현
@Override
public void doPrinting() {
System.out.println("플라스틱 재료로 출력합니다.");
}
// toString 재구현
@Override
public String toString() {
return "재료는 플라스틱 입니다.";
}
}
Material 클래스를 상속받으며 추상메서드를 재정의하고,
toString 메서드도 재정의 했다.
Powder.java
public class Powder extends Material {
// 추상메서드 재구현
@Override
public void doPrinting() {
System.out.println("파우더 재료로 출력합니다.");
}
// toString 재구현
@Override
public String toString() {
return "재료는 파우더 입니다.";
}
}
Plastic 클래스와 동일하게
Material 클래스를 상속받으며 추상메서드를 재정의하고,
toString 메서드도 재정의 했다.
GenericPrinter.java
public class GenericPrinter<T extends Material> {
// 멤버변수
private T material;
// getter setter
public T getMaterial() {
return material;
}
public void setMaterial(T material) {
this.material = material;
}
@Override
public String toString() {
return material.toString();
}
}
클래스명 뒤에 <T extends Material> 을 붙여줌으로써
Material 클래스를 상속받은 클래스만 넣을 수 있도록 강제성의 부여한다.
Material을 상속받은 T 타입의 자료형인 material 변수를 priavate로 선언하여
외부에서 간접적으로 접근할 수 있는 getter setter 을 생성해주었고,
각 재료의 클래스에 재정의 되어있는 toString 도 연결시켜주며 재정의하였다.
TExtendsClass.java
// extends Material을 하지 않은 class
class Water {
@Override
public String toString() {
return "재료는 물 입니다.";
}
}
// 구현 클래스
public class TExtendsClass {
public static void main(String[] args) {
GenericPrinter<Powder> powderPrinter = new GenericPrinter<>();
powderPrinter.setMaterial(new Powder());
Powder powder = powderPrinter.getMaterial();
System.out.println(powder.toString());
System.out.println("--------------------");
GenericPrinter<Water> waterPrinter = new GenericPrinter<Water>();
// extends Material 한 클래스가 아니기 때문에 오류 발생!
}
}
확실한 비교를 위해서 main함수가 있는 클래스 범위 밖에
Material 클래스를 상속받지 않은 Water 클래스를 생성해주어서,
toString 메서드만 재정의해주었다.
main 함수 안에 Powder 재료를 매개변수로 받는 GenericPrinter를
powderPrint의 이름으로 객체화 했다.
powderPrinter에 set 메서드로 Powder 를 재료로 설정해주고(new),
get 메서드로 반환되는 Powder 재료를 Powder 타입의 powder 변수에 담아주었고,
그 powder에 점연산자로 재정의 해 놓은 toString 메서드에 접근했다.
그래서 아래와 같이 재정의된 메서드들이 잘 실행되는 것을 확인할 수 있다.
반면,
Material을 상속받지 않은 Water 클래스는
Bound mismatch, Cannot infer type arguments for GenericPrinter<>
오류가 발생되며 WaterPrinter가 객체화되지 못했다.
이는 extends Material 한 클래스가 아니기 때문에 오류가 발생된 것이다.