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 |