KDT/Java

240325 Java - 제네릭 1

001cloudid 2024. 3. 25. 12:50
728x90

제네릭

 

  • 동일한 프로그램 코드에 다양한 데이터 타입(자료형)을 적용
  • 클래스 내부에서 사용할 변수의 형태를 외부에서 지정하는 방법으로 주로 멤버 변수의 자료형이나 메소드 반환 타입을 외부에서 지정해줄 때 사용
  • 클래스와 메소드들을 일반화시켜 제네릭 메소드와 제네릭 클래스를 만듦
  • 제네릭 메소드나 제네릭 클래스는 개발자가 원하는 데이터 타입으로 구체화시켜 메소드나 클래스의 프로그램 코드를 틀로 찍어 내듯 생산하는 기법
  • 어떤 클래스나 메소드에 모든 사용 가능한 자료형을 미리 명시해 주어 클래스를 선언할 때 타입을 결정하지 않고 객체 생성 시 유동적으로 재사용하기 위한 것
  • 제네릭을 활용하면 따로 형변환을 시켜 사용할 필요가 없고, 타입 에러가 발생하지 않기 때문에 유용하게 사용할 수 있음

 

제너릭 타입

  • 자료형을 매개변수로 가지는 클래스와 인터페이스
  • class 및 interface 이름 뒤 < > 를 적어주고 타입 매개변수를 명시
public class 클래스명<T>{ }

public interface 인터페이스명 <T> { }

 

 

컬렉션 클래스에서 타입 매개 변수(권고 사항)

E : Element

K : map Key

V : map Value

N : Number

T,S,U,V : 제너릭 타입

 

package test19;

public class Generic1 {
	
	public static void main(String[] args) {
	
		//Wrapper class : 기본 자료형을 객체형으로 변환하고 처리하는 클래스

		Byte type1 = 127;
		Short type2 = 255;
		Integer type3 = 1000;
		Long type4 = 10000L;
		
		Float type5 = 0.01F;
		Double type6 = 0.0000001;
		
		Boolean type7 = true;
		Character type8 = 'A';
		
		//객체 출력
		System.out.println(type1);
		System.out.println(type2);
		System.out.println(type3);
		System.out.println(type4);
		System.out.println(type5);
		System.out.println(type6);
		System.out.println(type7);
		System.out.println(type8);
		
		System.out.println();
		
		//객체의 클래스 출력
		System.out.println(type1.getClass().getName());
		System.out.println(type2.getClass().getName());
		System.out.println(type3.getClass().getName());
		System.out.println(type4.getClass().getName());
		System.out.println(type5.getClass().getName());
		System.out.println(type6.getClass().getName());
		System.out.println(type7.getClass().getName());
		System.out.println(type8.getClass().getName());
		
		System.out.println();
		
		
	}
}

 

package test19;

//제네릭 클래스(E => 요소값 지정)
class Gen1<E>{//제네릭 클래스
	
	private E element; //제네릭 타입 변수

	public E getElement() {
		return element;
	}

	public void setElement(E element) {
		this.element = element;
	}

	@Override
	public String toString() {
		return element.getClass().getName() +" "+ element;
	}
}


public class Generic1 {
	
	public static void main(String[] args) {
	
		//Wrapper class : 기본 자료형을 객체형으로 변환하고 처리하는 클래스

		Byte type1 = 127;
		Short type2 = 255;
		Integer type3 = 1000;
		Long type4 = 10000L;
		
		Float type5 = 0.01F;
		Double type6 = 0.0000001;
		
		Boolean type7 = true;
		Character type8 = 'A';
		
		//객체 출력
		System.out.println(type1);
		System.out.println(type2);
		System.out.println(type3);
		System.out.println(type4);
		System.out.println(type5);
		System.out.println(type6);
		System.out.println(type7);
		System.out.println(type8);
		
		System.out.println();
		
		//객체의 클래스 출력
		System.out.println(type1.getClass().getName());
		System.out.println(type2.getClass().getName());
		System.out.println(type3.getClass().getName());
		System.out.println(type4.getClass().getName());
		System.out.println(type5.getClass().getName());
		System.out.println(type6.getClass().getName());
		System.out.println(type7.getClass().getName());
		System.out.println(type8.getClass().getName());
		
		System.out.println();
		
		//제네릭 클래스 객체 생성
		//제네릭 클래스 객체 생성 시 < > 안에 생성할 객체 타입을 매개변수로 넘겨줌
		Gen1<String> a = new Gen1();
		//a 객체는 String형(객체) 이외의 다른 자료형은 대입할 수 없음
		a.setElement("제네릭");
		System.out.println(a.getElement()); 
		System.out.println(a.toString());
//		a.setElement(10); //지정해둔 데이터형만 들어갈 수 있음
		
		System.out.println();
		
		Gen1<Integer> b = new Gen1();
		b.setElement(10);
		System.out.println(b.getElement());
		System.out.println(b.toString());
		
		System.out.println();
		
		Gen1<Double> c = new Gen1();
		c.setElement(3.14);
		System.out.println(c.getElement());
		System.out.println(c.toString());
		
		
		
		
	}
}

 

package test19;

//제네릭 클래스(T => 타입)
class Gen2<T>{
	
	private T type;

	public T getType() {
		return type;
	}

	public void setType(T type) {
		this.type = type;
	}

	@Override
	public String toString() {
		return type.getClass().getName() + " " + type;
	}
}

public class Generic2 {

	public static void main(String[] args) {
		//Gen2 제네릭 클래스 객체 생성
		Gen2<String> a = new Gen2();
		a.setType("제네릭");
		System.out.println(a.getType());
		System.out.println(a.toString());
		System.out.println(a);
		
	}

}

 

제네릴 사용 시 따로 형변환을 시켜 사용할 필요가 없고 타입 에러가 발생하지 않기 때문에 유용하게 사용할 수 있음

//클래스명/인터페이스명 <타입> 변수명 = new 클래스명/인터페이스명[<타입>]();
//new 클래스명/인터페이스명 뒤에 <타입>은 생략 가능

 

< >를 생략했을 경우

package test19;

//제네릭 클래스(T => 타입)
class Gen2<T>{
	
	private T type;

	public T getType() {
		return type;
	}

	public void setType(T type) {
		this.type = type;
	}

	@Override
	public String toString() {
		return type.getClass().getName() + " " + type;
	}
}

public class Generic2 {

	public static void main(String[] args) {
		//Gen2 제네릭 클래스 객체 생성
		//타입(자료형) 매개 변수 T로 지정해서 객체 생성하는 예제
		Gen2<String> a = new Gen2();
		a.setType("제네릭");
		System.out.println(a.getType());
		System.out.println(a.toString());
		System.out.println(a);
		
		//제네릭 형태가 아닌 일반 객체 생성 형태 : Object형으로 자동 인식
		//Object형 : 모든 자료형이 올 수 있음
		Gen2 b = new Gen2();
		b.setType(100);
		System.out.println(b.toString());
		b.setType('A');
		System.out.println(b.toString());
		b.setType(3.14);
		System.out.println(b.toString());
		
		System.out.println();
		
		Gen2<Object> obj = new Gen2();
		obj.setType('A');
		System.out.println(obj.toString());
		obj.setType("Object형");
		System.out.println(obj.toString());
		obj.setType(100);
		System.out.println(obj.toString());
		obj.setType(3.14);
		System.out.println(obj.toString());

	}

}

 

package test19;

//제네릭 클래스(T => 타입)
class Gen2<T>{
	
	private T type;

	public T getType() {
		return type;
	}

	public void setType(T type) {
		this.type = type;
	}

	@Override
	public String toString() {
		return type.getClass().getName() + " " + type;
	}
}

public class Generic2 {

	public static void main(String[] args) {
		//Gen2 제네릭 클래스 객체 생성
		//타입(자료형) 매개 변수 T로 지정해서 객체 생성하는 예제
		Gen2<String> a = new Gen2();
		a.setType("제네릭");
		System.out.println(a.getType());
		System.out.println(a.toString());
		System.out.println(a);
		
		//제네릭 형태가 아닌 일반 객체 생성 형태 : Object형으로 자동 인식
		//Object형 : 모든 자료형이 올 수 있음
		Gen2 b = new Gen2();
		b.setType(100);
		System.out.println(b.toString());
		b.setType('A');
		System.out.println(b.toString());
		b.setType(3.14);
		System.out.println(b.toString());
		
		System.out.println();
		
		Gen2<Object> obj = new Gen2();
		obj.setType('A');
		System.out.println(obj.toString());
		obj.setType("Object형");
		System.out.println(obj.toString());
		obj.setType(100);
		System.out.println(obj.toString());
		obj.setType(3.14);
		System.out.println(obj.toString());
		
		System.out.println();
		System.out.println((int)'가');
		
		//객체형 형 변환을 했을 경우 컴파일 오류가 발생함
		obj.setType('A');
//		System.out.println((Integer)obj.toString());
		


	}

}

 

package test19;

//일반 클래스 형태 : 클래스를 만들 때 멤버들의 자료형이 지정됨
class Normal1{ //문자열 배열만 사용 가능
	private String[] str;

	public String[] getStr() {
		return str;
	}

	public void setStr(String[] str) {
		this.str = str;
	}
	
	public void show() {
		for(String s : str) {
			System.out.println(s);
		}
	}
	
}
class Normal2{ //정수형 배열만 사용 가능
	private Integer[] num;

	public Integer[] getNum() {
		return num;
	}

	public void setNum(Integer[] num) {
		this.num = num;
	}
	
	public void show() {
		for(Integer n : num) {
			System.out.println(n);
		}
	}
	
}

class Normal3{//Object형 배열 사용 가능(모든 자료형 사용 가능)
	private Object[] obj;
	
	public Object[] getObj() {
		return obj;
	}

	public void setObj(Object[] obj) {
		this.obj = obj;
	}

	public void show() {
		for(Object obj : obj) {
			System.out.println(obj);
		}
	}
	
}

class GenericClass<T>{
	T[] t;
	
	public T[] getT() {
		return t;
	}

	public void setT(T[] t) {
		this.t = t;
	}

	@Override
	public String toString() {
		return t.getClass().getName() +" "+ t;
	}
	
	public void show() {
		for(T obj : t) {
			System.out.println(obj);
		}
	
	}
}

public class Generic3 {

	public static void main(String[] args) {
		
		//제네릭 클래스로 객체 생성
		GenericClass<String> gcStr = new GenericClass();
		//String 타입 매개 변수 T : String[] 객체 전달
		String[] s1 = {"A","B","C"};
		gcStr.setT(s1);
		gcStr.show();
		//하나씩 꺼내오기
		System.out.println("하나씩 꺼내오기");
		for(String str : gcStr.getT()) {
			System.out.println(str);
		}
		
		System.out.println();
		
		
		GenericClass<Integer> gcInt = new GenericClass();
		//Integer 타입 매개 변수 T : Integer[] 객체 전달
		Integer[] s2 = {1,2,3,4};
		gcInt.setT(s2);
		gcInt.show();
		System.out.println("하나씩 꺼내오기");
		for(Integer integer : gcInt.getT()) {
			System.out.println(integer);
		}
		
       //객체 내 요소값을 꺼내올 때 String, Integer 등 자료형만 지정해두기 때문에 형 변환이 필요없음.

	}

}

 

제네릭을 사용하면 자료형을 쉽게 지정할 수 있어 보다 편함

 

package test19;


//객체를 생성해서 사용할 클래스
class Powder{

	public void doPrinting() {
		System.out.println("Powder 재료로 출력");
	}
	
	@Override
	public String toString() {
		return "재료는 Powder";
	}
}

//객체를 생성해서 사용할 클래스
class Plastic{
	public void doPrinting() {
		System.out.println("Plastic 재료로 출력");
	}

	@Override
	public String toString() {
		return "재료는 Plastic";
	}
	
}
//제네릭 클래스 클래스의 구조를 일반화 시킨 클래스
class GenericPrint<T>{
	private T material; //제네릭 타입 변수

	public T getMaterial() { //제네릭 타입 메소드
		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) {
		GenericPrint<Powder> powder = new GenericPrint();
		powder.setMaterial(new Powder());
		System.out.println(powder.getMaterial());
		System.out.println(powder);
		
		System.out.println();
		
		GenericPrint<Plastic> plastic = new GenericPrint();
		plastic.setMaterial(new Plastic());
		System.out.println(plastic.getMaterial());
		System.out.println(plastic);
		System.out.println();
		
		//제네릭 클래스에 대입시킬 자료형을 명시하지 않는 경우 => Object형
		//컴파일 오류는 아니지만 강제로 사용할 타입으로 형 변환을 시켜줘야함
		GenericPrint powder1 = new GenericPrint();
		powder1.setMaterial(new Powder());
//		powder1.setMaterial(new Plastic());
		Powder p = (Powder)powder1.getMaterial();
		System.out.println(powder1);
		System.out.println(p);
		System.out.println((Powder)powder1.getMaterial());
		System.out.println();
		
		//강제로 사용할 타입으로 형 변환 시켜줘야함
		GenericPrint<Object> gp = new GenericPrint();
		gp.setMaterial(new Powder());
		
		Powder pp = (Powder)gp.getMaterial();
		System.out.println(gp);
		System.out.println(pp);
		System.out.println((Powder)gp.getMaterial());

	}

}

 

 

 

 

 

728x90

'KDT > Java' 카테고리의 다른 글

240328 Java - 컬렉션 프레임워크 1  (0) 2024.03.28
240327 Java - 제네릭 2  (0) 2024.03.27
240321 Java - 스레드 3  (0) 2024.03.21
240320 Java - 스레드 2  (0) 2024.03.20
240318 Java - 스트림 3, 스레드 1  (0) 2024.03.18