본문 바로가기

Java

제네릭 ( Generic )

제네릭이란?

제네릭 프로그래밍은 자바에서 타입을 일반화하여 재사용 가능한 코드를 작성하는 기법이다. 제네릭을 사용하면 클래스, 인터페이스, 메서드 등에 대해 특정 타입을 지정하지 않고, 다양한 타입에서 동작하도록 할 수 있다. 이는 코드의 재사용성과 안정성을 높여준다.

 

제네릭 프로그래밍의 주요 이점

  1. 타입 안정성 : 컴파일 시 타입을 검사하여 런타임 에러를 줄일 수 있다.
  2. 코드 재사용성 : 다양한 타입을 처리할 수 있는 일반화된 코드를 작성할 수 있다.
  3. 유지보수성 : 타입 캐스팅을 줄여 가독성과 유지보수성을 향상시킨다.
package ch01;

public class Plastic {
	
	@Override
	public String toString() {
		
		return "재료는 플라스틱 입니다";
	}
}
package ch01;

public class Powder {

	
	@Override
	public String toString() {
		return "재료는 파우더 입니다";
	}
}
package ch01;

public class ThreeDPrinter {
	
	Plastic material; 
	
	// get,set 
	public Plastic getMaterial() {
		return material;
	}
	
	public void setMaterial(Plastic material) {
		this.material = material;
	}
	
}
package ch01;

public class ThreeDPrinter2 {
	
	Powder material; 
	
	// get,set 
	public Powder getMaterial() {
		return material;
	}
	
	public void setMaterial(Powder material) {
		this.material = material;
	}
	
}
package ch01;

/**
 * 컴파일 시점에 material 데이터 타입으로는 
 * 모든 클래스가 될 수 있다. 
 */
public class ThreeDPrinter3 {
	
	Object material; 
	
	// get,set 
	public Object getMaterial() {
		return material;
	}
	
	public void setMaterial(Object material) {
		this.material = material;
	}
	
}
package ch01;

public class MainTest1 {

	public static void main(String[] args) {
		
		ThreeDPrinter dPrinter1 = new ThreeDPrinter();
		dPrinter1.setMaterial(new  Plastic());
		System.out.println(dPrinter1.material.toString());
		// 위 ThreeDPrinter 한계는 재료가 플라스틱에 종속 되어있다. 
		// 하자만 사용자 입장에서 재료를 파우더로 변경한다면 
		// 코드에 수정이나 새로운 클래스가 필요하다.
		System.out.println("--------------------");
		ThreeDPrinter2 dPrinter2 = new ThreeDPrinter2();
		dPrinter2.setMaterial(new  Powder());
		System.out.println(dPrinter2.material.toString());
		
		System.out.println("============================");
		
		ThreeDPrinter3 dPrinter3 = new ThreeDPrinter3();
		dPrinter3.setMaterial(new Plastic());
		System.out.println(dPrinter3.material.toString());
		
		System.out.println("----------------------------");
		
		ThreeDPrinter3 dPrinter3_2 = new ThreeDPrinter3();
		dPrinter3_2.setMaterial(new Powder());
		System.out.println(dPrinter3_2.material.toString());
		
		Plastic plastic01 = (Plastic)dPrinter3.getMaterial(); // 다운 캐스팅
		Powder powder01 = (Powder)dPrinter3.getMaterial(); // 오류나는 코드가 된다.
	}

}

package ch02;

public class GenericPrinter<T> {

	// T 라는 대체 문자를 사용, E - element, K - key, V - value(사실은 아무 문자나 가능하다) 
	// 자료형 매개변수(type parameter) 
	// 이 클래스를 사용하는 시점에서 실제 사용될 자료형이 결정 된다. 
	
	private T material;  // T 대체 문자형으로 변수를 선언 
	
	// get,set 
	public T getMaterial() {
		return material;
	}
	
	public void setMaterial(T material) {
		this.material = material;
	}
	// GenericPrinter<T> -- 참조 변수를 sysout(참조변수) --> 나의 멤버 material에 toString() 설계함
	@Override
	public String toString() {
		return material.toString();
	}
}
package ch02;

import ch01.Plastic;
import ch01.Powder;

public class MainTest2 {

	
	public static void main(String[] args) {
		
		// 재료 선언 
		Plastic plastic01 = new Plastic();
		Powder powder01 = new Powder();
		
		// 사용하는 시점에 T 대신 어떤 자료형을 사용할지 지정을 하면된다. 
		GenericPrinter<Plastic> genericPrinter1 = new GenericPrinter<>();
		genericPrinter1.setMaterial(plastic01); // 메서드 의존 주입 
		
		// 최상위 Object 를 활용할때와 비교 
		// 형변환 할 필요가 없다 (다운 캐스트)
		Plastic returnPlastic = genericPrinter1.getMaterial();
		System.out.println(returnPlastic);
		
		// 컴파일 시점에 오류를 알려줘서 안정적인 코드 작업이 진행 된다. 
		// Powder returnPowder = genericPrinter1.getMaterial(); <-- 오류 발생
		

	} // end of main 

}

package ch03;

// 직접 객체를 사용할 수 없게 강제성을 부여 - 추상 클래스 
public abstract class Material {
	
	public abstract void doPrinting();
}
package ch03;

/**
 * T extends 클래스 문법을 사용하기 위해 설계 
 */
public class Plastic extends Material {
	
	@Override
	public String toString() {
		return "재료는 플라스틱 입니다";
	}
	
	@Override
	public void doPrinting() {
		System.out.println("플라스틱 재료로 출력 합니다.");
	}

}
package ch03;

/**
 * T extends 클래스 문법을 사용하기 위해 설계 
 */
public class Powder extends Material {
	
	@Override
	public String toString() {
		return "재료는 파우더 입니다";
	}
	
	@Override
	public void doPrinting() {
		System.out.println("파우더 재료로 출력 합니다.");
	}

}
package ch03;

/**
 * 
 * @param <T> Material Material 를 상속받은 자식 클래스만 대체 문자에 들어올 수 있다.
 */
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();
	}
}
package ch03;

import ch02.Water;

public class MainTest3 {

	public static void main(String[] args) {
		
		// <T extends 클래스> 사용하기 
		
		// 상위 클래스의 필요성 
		// T 자료형은 범위를 제한할 수 없음 
		// 위 문법 사용해서 상위 클래스에 속한 자료형만 대체 문자 안에 들어올 수 있다. 
		
		// ch03 패키지 자료형 사용 
		GenericPrinter<Powder> genericPrinter1 = new GenericPrinter<>();
		genericPrinter1.setMaterial(new Powder());
		System.out.println(genericPrinter1.toString());
		
		/////////////////////////////////////////////////
		
		// 컴파일시점에서 부터 오류 발생을 한다. 
		// GenericPrinter<Water> genericPrinter2 = new GenericPrinter<>();

	}

}
728x90

'Java' 카테고리의 다른 글

순수 자바코드로 HttpServer 만들기  (0) 2024.06.03
소켓을 활용한 HTTP 통신  (0) 2024.06.03
네트워크 프로토콜  (0) 2024.05.24
1:1 양방향 통신 (채팅 기본 기능 구현)  (0) 2024.05.24
1 : 1 양방향 통신  (0) 2024.05.24