제네릭

프로그래밍/Java 2019. 12. 14. 14:35

제네릭은 하나의 변수가 하나의 참조 자료형만 가지는게 아닌, 여러개의 참조자료형을 가질 수 있는 기능 중 하나이다.

만약 3D 프린터로 무언가를 만든다고 했을 때 그 안에 있는 재료는 무엇이든 될 수 있다.
그 재료가 바뀔 때마다 그 재료에 맞는 프린터를 사용하는 것은 비효율적이고, 비용이 많이 든다. 제네릭은 동일한 프린터기에 다른 재료들을 넣어서 생산할 수 있게끔 도와준다.

Powder 클래스

package generics;

public class Powder {
    public void doPrinting() {
        System.out.println("Poder 재료로 출력합니다.");
    }

    @Override
    public String toString() {
        return "재료는 Powder 입니다";
    }

}

Plastic 클래스

package generics;

public class Plastic {
    public void doPrinting() {
        System.out.println("Plastic 재료로 출력합니다.");
    }

    @Override
    public String toString() {
        return "재료는 Plastic 입니다";
    }

}

GenericPrinter

package generics;

public class GenericPrinter<T> {
    private T material;

    public void setMaterial(T material) {
        this.material = material;
    }

    public T getMaterial() {
        return material;
    }

    public String toString() {
        return material.toString();
    }
}
  • 이 3D 프린터기는 어떤 재료로도 제품을 생산할 수 있다.

GenericPrinterTest - 프린트 출력

package generics;

public class GenericPrinterTest {
    public static void main(String[] args) {
        GenericPrinter<Powder> powderPrinter = new GenericPrinter<Powder>();

        powderPrinter.setMaterial(new Powder());
        Powder powder = powderPrinter.getMaterial();
        System.out.println(powderPrinter);

        GenericPrinter<Plastic> plastiPrinter = new GenericPrinter<Plastic>();

        plastiPrinter.setMaterial(new Plastic());
        Plastic plastic = plastiPrinter.getMaterial();
        System.out.println(plastiPrinter);                    


    }
}

  • 각각 플라스틱과, 파우더 재료를 넣어 제품을 생산하였다.

제네릭의 T 자료형 제한.

만약 재료를 넣는데 엉뚱한 재료를 넣는다면, 프린터기가 망가질 수 있다. 그렇기 때문에 제네릭 자료형의 제한을 할 수 있다.

Material 클래스

package generics;

public abstract class Material {
    public abstract void doPrinting();
}

기존재료들은 Material 클래스를 상속받음.

package generics;

public class Powder extends Material {
    public void doPrinting() {
        System.out.println("Poder 재료로 출력합니다.");
    }

    @Override
    public String toString() {
        return "재료는 Powder 입니다";
    }

}
package generics;

public class Plastic extends Material {
    public void doPrinting() {
        System.out.println("Plastic 재료로 출력합니다.");
    }

    @Override
    public String toString() {
        return "재료는 Plastic 입니다";
    }

}

제네릭 클래스에도 Material를 상속받는다.

package generics;

public class GenericPrinter<T extends Material> {
    private T material;

    public void setMaterial(T material) {
        this.material = material;
    }

    public T getMaterial() {
        return material;
    }

    public String toString() {
        return material.toString();
    }

    public void printing() {
        material.doPrinting();
    }
}

테스트

  • Material 클래스를 상속받지 않은 클래스를 제네릭 자료형으로 넘기면 오류가 발생!

  • 이 친구도 상속을 받았다.

  • 이제 오류가 안남.


제네릭 클래스에서 상위 클래스 메서드 사용하기.

GenericPrinter 클래스에 메서드 추가.

테스트

package generics;

public class GenericPrinterTest {
    public static void main(String[] args) {
        GenericPrinter<Powder> powderPrinter = new GenericPrinter<Powder>();

        powderPrinter.setMaterial(new Powder());
        Powder powder = powderPrinter.getMaterial();
//        System.out.println(powderPrinter);
        powderPrinter.printing();

        GenericPrinter<Plastic> plastiPrinter = new GenericPrinter<Plastic>();

        plastiPrinter.setMaterial(new Plastic());
        Plastic plastic = plastiPrinter.getMaterial();
//        System.out.println(plastiPrinter);     
        plastiPrinter.printing();


        // Material 을 상속하지 않은 클래스
        GenericPrinter<Water> water = new GenericPrinter<Water>();        


    }
}


여러개의 제네릭 자료형 받기.

제네릭 클래스

package generics;

public class Point<T, V> {
    T x;
    V y;

    public Point(T x, V y) {
        this.x = x;
        this.y = y;
    }

    public T getX() {
        return x;
    }

    public V getY() {
        return y;
    }


}

제네릭 메서드 구현

package generics;

public class GenericMethod {
    public static <T, V> double makeRectangle(Point<T, V> p1, Point<T, V> p2) {
        double left = ((Number)p1.getX()).doubleValue();   // 0
        double right = ((Number)p2.getX()).doubleValue();  // 10
        double top = ((Number)p1.getY()).doubleValue();    // 0.0
        double bottom = ((Number)p2.getY()).doubleValue(); // 10.0

        double width = right - left; // 10 - 0 = 10
        double height = bottom - top; // 10.0 - 0.0 = 10.0

        return width * height; // 10 * 10.0 = 100.0
    }

    public static void main(String[] args) {
        Point<Integer, Double> p1 = new Point<>(0, 0.0);
        Point<Integer, Double> p2 = new Point<>(10, 10.0);

        double rect = GenericMethod.<Integer, Double>makeRectangle(p1, p2);
        System.out.println("두 점으로 만들어진 사각형의 넓이는 " + rect + "입니다.");
    }
}
  • GenericMethod는 제네릭 클래스가 아니더라도 내부에 있는 제네릭 메서드를 구현할 수 있다.
  • 제네릭 메서드는 static 으로 선언하였다.
  • 제네릭 메서드의 매개변수 들어오는 자료형은 해당 메서드 안에서만 유효범위를 갖는다.



출처: do it 자바프로그래밍

'프로그래밍 > Java' 카테고리의 다른 글

Set  (0) 2019.12.17
컬렉션 프레임워크  (0) 2019.12.14
Class 클래스  (0) 2019.12.12
wrapper클래스  (0) 2019.12.11
String 클래스  (0) 2019.12.10
블로그 이미지

파니동

,