ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 20. Generic 프로그래밍
    개발자 수업/Java 2021. 10. 14. 20:37
    public class Plastic {
    
    	@Override
    	public String toString() {
    		return "재료는 Plastic 입니다.";
    	}
    }
    
    
    
    public class Powder {
    	
    	@Override
    	public String toString() {
    		return "재료는 Powder 입니다.";
    	}
    	
    	
    }
    public class ThreeDPrinter01 {
    	
    	private Powder material;
    
    	public Powder getMaterial() {
    		return material;
    	}
    
    	public void setMaterial(Powder material) {
    		this.material = material;
    	}
    	
    	@Override
    	public String toString() {
    		return "재료는 Powder 입니다.";
    	}
    	
    }
    
    
    
    
    public class ThreeDPrinter02 {
    	
    	private Plastic material;
    
    	public Plastic getMaterial() {
    		return material;
    	}
    
    	public void setMaterial(Plastic material) {
    		this.material = material;
    	}
    	
    	@Override
    	public String toString() {
    		return "재료는 Plastic 입니다.";
    	}
    	
    }
    
    
    
    
    
    public class ThreeDPrinter03 {
    	
    	private Object material;
    
    	public Object getMaterial() {
    		return material;
    	}
    
    	public void setMaterial(Object material) {
    		this.material = material;
    	}
    	
    //	@Override
    //	public String toString() {
    //		return "재료는 Object 입니다.";
    //	}
    	
    }
    
    
    
    
    public class ThreeDPrinterTest {
    
    	public static void main(String[] args) {
    		Powder powder = new Powder();
    		ThreeDPrinter03 printer = new ThreeDPrinter03();
    		printer.setMaterial(powder);
    		
    		// 재료를 꺼내는 경우에 형변환이 필요함 -> 번거로움, 성능 이슈 발생 -> 제네릭 프로그래밍 도입
    		Powder powder2 = (Powder)printer.getMaterial();
    	}
    }
    /*
     * 	1) 자료형 매개변수 T(type parameter) : 이 클래스를 사용하는 시점에 실제 사용할 자료형을 지정
     * 	2) GenericPrinter : 제네릭 자료형
     * 	3) E : element
     * 	   K : key
     *     V : value
     *     T : type 등 여러 알파벳을 의미에 따라 사용 가능
     */	
    public class GenericPrinter<T> {
    
    	private T material;					// T 자료형으로 선언한 참조변수
    
    	public T getMaterial() {			// T 자료형으로 반환하는 제네릭 메서드
    		return material;
    	}
    
    	public void setMaterial(T material) {
    		this.material = material;
    	}
    	
    	@Override
    	public String toString() {
    		return material.toString();
    	}
    }
    
    
    
    
    
    
    
    public class GenericPrinterTest {
    
    	public static void main(String[] args) {
    		Powder powder = new Powder();
    		
    		// <> : 다이아몬드 연산자
    		GenericPrinter<Powder> pGenericPrinter = new GenericPrinter<>();
    		pGenericPrinter.setMaterial(powder);
    		
    		// 재료를 꺼내는 경우에 형변환이 불필요
    		Powder powder2 = pGenericPrinter.getMaterial();
    		
    		System.out.println(pGenericPrinter.toString());	// 재료는 Powder 입니다.
    		
    		
    		GenericPrinter<Plastic> plaGenericPrinter = new GenericPrinter<>();
    		plaGenericPrinter.setMaterial(new Plastic());
    		Plastic plastic = plaGenericPrinter.getMaterial();
    		System.out.println(plaGenericPrinter.toString());	// 재료는 Plastic 입니다.
    	}
    }

     

    1. 제네릭의 개요
        1) 제네릭 타입 : 타입을 파라미터화 하여 실행 시에 구체적으로 해당하는 타입으로 결정이 되는 것
        2) 제네릭을 사용하면 컴파일 시 강한 타입 체크 뿐만 아니라 타입 변환(casting) 사전에 제거함 -> 앱의 성능 저하를 막음
        3) 타입을 파라미터로 갖는 클래스 또는 인터페이스를 의미함
            - 선언할 때 클래스 또는 인터페이스명 뒤에 <> 가 붙음
            - 보통 알파벳 한 문자로 표식을 함 <T>
        4) 컬렉션 프레임워크에서 많이 사용하고 있음

    // 제네릭 클래스인데 타입 파라미터 2개
    public class Product<T, M> {
    	
    	private T t;
    	private M m;
    	
    	public T getT() {
    		return t;
    	}
    	public void setT(T t) {
    		this.t = t;
    	}
    	public M getM() {
    		return m;
    	}
    	public void setM(M m) {
    		this.m = m;
    	}
    }
    
    
    
    
    
    
    public class Car {
    
    	private String brand;
    	private int year;
    	private int month;
    	
    	public Car() {}	// 기본 생성자
    
    	public Car(String brand, int year, int month) {
    		super();
    		this.brand = brand;
    		this.year = year;
    		this.month = month;
    	}
    
    	public String getBrand() {
    		return brand;
    	}
    
    	public void setBrand(String brand) {
    		this.brand = brand;
    	}
    
    	public int getYear() {
    		return year;
    	}
    
    	public void setYear(int year) {
    		this.year = year;
    	}
    
    	public int getMonth() {
    		return month;
    	}
    
    	public void setMonth(int month) {
    		this.month = month;
    	}
    	
    }
    
    
    
    
    
    public class TV {
    
    	private int year;
    	private int month;
    	
    	public TV() {}
    
    	public TV(int year, int month) {
    		super();
    		this.year = year;
    		this.month = month;
    	}
    
    	public int getYear() {
    		return year;
    	}
    
    	public void setYear(int year) {
    		this.year = year;
    	}
    
    	public int getMonth() {
    		return month;
    	}
    
    	public void setMonth(int month) {
    		this.month = month;
    	}	
    }
    
    
    
    
    
    
    public class ProductTest {
    
    	public static void main(String[] args) {
    		Product<TV, String> product = new Product<>();
    		product.setT(new TV(2021,10));
    		product.setM("LG OLED AI TV");
    		System.out.println("나의 TV는 " + product.getT().getYear() + "년 " + 
    										product.getT().getMonth() + "월 식이며, " + 
    										product.getM() + "이다." );
    		// 나의 TV는 2021년 10월 식이며, LG OLED AI TV이다.
    		
    		Product<Car, String> product2 = new Product<>();
    		product2.setT(new Car("현대", 2021, 10));
    		product2.setM("펠리세이드 캐리그래피");
    		Car car = product2.getT();
    		String str = product2.getM();
    		System.out.println("나의 Car는 " + car.getYear() + "년 " + 
    										car.getMonth() + "월 출시된, " + 
    										car.getBrand() + "의 " + str + "이다." );
    		// 나의 Car는 2021년 10월 출시된, 현대의 펠리세이드 캐리그래피이다.                        
    	}
    }



    2. 멀티 타입 파라미터 
        1) 제네릭은 2개 이상의 타입 파라미터를 사용해서 선언할 수 있음
        2) 각 타입 파라미터는 콤마(,)로 구분함

    public class Plastic extends Material {
    
    	@Override
    	public void doPrinting() {
    		System.out.println("Plastic 재료로 출력합니다.");	
    	}
    	
    	@Override
    	public String toString() {
    		return "재료는 Plastic 입니다.";
    	}
    
    }
    
    
    
    public class Powder extends Material {
    
    	@Override
    	public void doPrinting() {
    		System.out.println("Powder 재료로 출력합니다.");
    	}
    	
    	@Override
    	public String toString() {
    		return "재료는 Powder 입니다.";
    	}
    
    }
    
    
    
    
    public class Water {
    
    }
    
    
    
    public abstract class Material {
    
    	public abstract void doPrinting();
    }
    public class GenericPrinter<T extends Material> {
    	
    	private T material;
    
    	public T getMaterial() {
    		return material;
    	}
    
    	public void setMaterial(T material) {
    		this.material = material;
    	}
    	
    	@Override
    	public String toString() {
    		return material.toString();
    	}
    	
    	public void printing() {
    		material.doPrinting();
    	}
    
    }
    
    
    
    
    
    
    public class GenericPrinterTest {
    
    	public static void main(String[] args) {
    		GenericPrinter<Powder> powderPrinter = new GenericPrinter<>();
    		powderPrinter.setMaterial(new Powder());
    		Powder powder = powderPrinter.getMaterial();
    		System.out.println(powderPrinter);	// 재료는 Powder 입니다.
    		
    		GenericPrinter<Plastic> plasticPrinter = new GenericPrinter<>();
    		plasticPrinter.setMaterial(new Plastic());
    		Plastic plastic = plasticPrinter.getMaterial();
    		System.out.println(plasticPrinter);	// 재료는 Plastic 입니다.
    		
    		GenericPrinter powderPrinter2 = new GenericPrinter();
    		powderPrinter2.setMaterial(new Powder());
    		Powder powder2 = (Powder)powderPrinter2.getMaterial();
    		
    		// GenericPrinter<Water> printer = new GenericPrinter<>(); 불가능
    		
    	}
    }



    3. <T extends 클래스> 사용하기
        1) 상위클래스의 필요성
            - T 자료형의 범위를 제한할 수 있음
            - 상위 클래스에서 선언하거나 정의하는 메서드를 사용할 수 있음
            - 상속을 받지 않는 경우 T는 Object 클래스가 기본으로 제공하는 메서드만 사용 가능

    4. 제네릭 메서드
        1) 매개변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메서드를 말함
        2) 제네릭 메서드는 리턴 타입 앞에 꺽쇠 기호를 추가하고 타입 파라미터를 기술하며 리턴타입과 매개변수에 사용함
        3) public <자료형 매개변수> 반환형 메서드 이름(자료형 매개변수) {}
        4) 제네릭 클래스가 아니어도 내부에 제네릭 메서드를 구현하여 사용할 수 있음

     

    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;
    	}
    	
    	
    }
    public class GenericMethodTest {
    
    	public static <T, V> double  makeRectangle(Point<T, V> point1, Point<T, V> point2) {
    		double left = ((Number)point1.getX()).doubleValue();
    		double right = ((Number)point2.getX()).doubleValue();
    		double top = ((Number)point1.getY()).doubleValue();
    		double bottom = ((Number)point2.getY()).doubleValue();
    		
    		double width = right - left;
    		double height = bottom - top;
    		
    		return width * height; 
    		
    	}
    	
    	public static void main(String[] args) {
    		Point<Integer, Double> point1 = new Point<>(0, 0.0);
    		Point<Integer, Double> point2 = new Point<>(10, 10.0);
    		double size = GenericMethodTest.makeRectangle(point1, point2);
    		System.out.println(size);	// 100.0
    		
    	}
    }

    '개발자 수업 > Java' 카테고리의 다른 글

    22. Review  (0) 2021.10.18
    21. 컬렉션 프레임워크  (0) 2021.10.14
    19. Wrapper 클래스  (0) 2021.10.14
    18. Class 클래스  (0) 2021.10.14
    17. String 클래스  (0) 2021.10.13

    댓글