제너릭 (Generic)
Generic
클래스 선언 및 객체화 할 때 원하는 타입만을 넣기 위해서 쓰는 것
-> 어떤 타입이 들어 있는지 정보가 없기 때문에 확인 작업이 필요하다.
-> 제네릭을 사용하면 확인 작업을 안해도 된다.
package chap08.ex03.obj;
public class Box {
private Object value; // 이 안에 뭐가 들어올지 몰라서 Object로 만들어 둔다.
public void setValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
}
package chap08.ex03.obj;
public class Main {
public static void main(String[] args) {
// 박스에 무엇인가 넣는다.
Box box = new Box();
box.setValue(123);
// 박스에서 물건을 꺼낸다.
// box에 무엇이 들었는지 정보가 없음
// 그래서 확인 작업이 필요
int val = (int)box.getValue();
System.out.println(val);
}
}
Generic 사용법
클래스나 인터페이스 선언 시 <T>를 붙인다.
T의 타입에 따라 데이터 타입이 변경된다.
package chap08.ex04.generic;
public class Box<T> { // 뭐가 들어올지 모르므로 일단 T라고 해둔다.
private T value; // T 타입에 따라 변수의 데이터 타입이 변경된다.
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
package chap08.ex04.generic;
public class Main {
public static void main(String[] args) {
// 박스에 들어갈 물건의 종류를 명시해준다.
Box<Integer> box = new Box<Integer>();
box.setValue(123);
// 박스를 열어본다.
// 내용물을 알 수 있으므로 확인이 필요없다.
int val = box.getValue();
System.out.println(val);
}
}
복수개의 제네릭을 사용 가능하다. (콤마로 구분하여)
package chap08.ex05.multi;
public class MultiBox<K,V> { // 두 개의 타입을 지정할 수 있다.
private K key;
private V value;
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
package chap08.ex05.multi;
public class Main {
public static void main(String[] args) {
// 첫 변수는 String 타입, 두 번째 변수는 Integer가 데이터 타입이 된다.
MultiBox<String, Integer> box = new MultiBox<String, Integer>();
//넣기
box.setKey("홍길동");
box.setValue(90);
//꺼내기
String name = box.getKey();
int score = box.getValue();
System.out.println(name+" : " + score);
}
}
Generic의 클래스 사용
객체화 부분 제네릭에 데이터 타입을 명시하지 않아도 작동은 하지만 이를 다이아몬드 연산자라고 부른다 -> 사용은 편리하지만 효율성이 떨어진다.
package chap08.ex06.multi;
public class Employee<A,B,C,D,E,F,G,H> {
private A number;
private B name;
private C age;
private D money;
private E asset;
private F pay;
private G marry;
private H hobby;
public A getNumber() {
return number;
}
public void setNumber(A number) {
this.number = number;
}
public B getName() {
return name;
}
public void setName(B name) {
this.name = name;
}
public C getAge() {
return age;
}
public void setAge(C age) {
this.age = age;
}
public D getMoney() {
return money;
}
public void setMoney(D money) {
this.money = money;
}
public E getAsset() {
return asset;
}
public void setAsset(E asset) {
this.asset = asset;
}
public F getPay() {
return pay;
}
public void setPay(F pay) {
this.pay = pay;
}
public G getMarry() {
return marry;
}
public void setMarry(G marry) {
this.marry = marry;
}
public H getHobby() {
return hobby;
}
public void setHobby(H hobby) {
this.hobby = hobby;
}
}
package chap08.ex06.multi;
public class Main {
// 제너릭 타입을 클래스로 사용하지 않은 경우
public static void main(String[] args) {
// 객체화 부분 제너릭에 데이터 타입을 명시해주지 않는 것을 다이아몬드 연산자라고 부른다.
// 사용은 편리하지만 효율성이 떨어진다.
Employee<Integer, String, Integer, Integer, Long, Float, Boolean, String> emp = new Employee<>();
// 데이터 넣기
emp.setAge(25);
emp.setAsset((long) 50000000);
emp.setHobby("독서");
emp.setMarry(true);
emp.setMoney(10000);
emp.setName("홍길동");
emp.setNumber(12);
emp.setPay(1.0f);
// 데이터 가져오기
int age = emp.getAge();
System.out.println(age);
}
}
제네릭 부분이 길어질 경우 클래스를 사용할 수 있다.
클래스를 사용하지 않을 때 데이터를 setter/getter로 바로 꺼내올 수 있지만 코드가 길어지고 실수가 생길 수 있다는 단점이 있다.
클래스를 사용한다면 데이터를 넣고 가져오는데 한 번씩의 작업을 더 해야하지만 코드를 줄일 수 있다. (제네릭이 많을 때 유리하다.)
package chap08.ex07.classtype;
public class Info {
private int emp_no;
private String name;
private int age;
private int salary;
private long assets;
private float commision;
private boolean married;
private String hobby;
public int getEmp_no() {
return emp_no;
}
public void setEmp_no(int emp_no) {
this.emp_no = emp_no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public long getAssets() {
return assets;
}
public void setAssets(long assets) {
this.assets = assets;
}
public float getCommision() {
return commision;
}
public void setCommision(float commision) {
this.commision = commision;
}
public boolean isMarried() {
return married;
}
public void setMarried(boolean married) {
this.married = married;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
package chap08.ex07.classtype;
public class Employee <T>{
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
package chap08.ex07.classtype;
public class Main {
// 제너릭 타입을 클래스로 사용한 경우
public static void main(String[] args) {
Employee<Info> emp = new Employee<Info>();
// 데이터 넣기
Info info = new Info();
info.setAge(25);
info.setAssets(1000000);
info.setCommision(1.0f);
info.setEmp_no(2);
info.setHobby("영화");
info.setMarried(false);
info.setName("김철수");
info.setSalary(10000);
emp.setT(info);
//데이터 가져오기
info = emp.getT();
int age = info.getAge();
System.out.println(age);
}
}
method에서 Generic 사용
메소드에서 제네릭을 사용하면 각각 다른 매개변수 타입을 사용할 수 있다.
-> 상황에 따라 유연하게 사용 가능하다.
반환이 없는 메소드일 경우 접근제한자와 void 사이에 제네릭을 쓰고 매개변수도 제네릭 타입으로 사용한다.
반환이 있는 메소드일 경우 메소드의 반환타입도 제네릭 타입으로 적어야한다.
package chap08.ex08.gmethod;
public class Gmethod {
// 제너릭을 사용하면 사용 시마다 각각 다른 매개변수 타입을 사용할 수 있다.
public <T> void method1(T t) {
System.out.println("입력값 : " + t);
}
// 받은 그대로 반환해 주는 경우
public <T> T method2(T t) {
return t;
}
}
package chap08.ex08.gmethod;
public class Main {
public static void main(String[] args) {
Gmethod gm = new Gmethod();
gm.method1(100);
gm.method1("감자");
System.out.println(gm.method2("고구마"));
System.out.println(gm.method2(true));
}
}
Generic의 상속
클래스에서 자식의 생성자 매개변수를 받아 부모의 생성자에 전달한 것처럼 자식에서 부모에서 사용할 제네릭 타입을 받아서 전달해야 한다.
package chap08.ex09.inherit;
public class BasicInfo<N,A> {
private N name;
private A age;
public N getName() {
return name;
}
public void setName(N name) {
this.name = name;
}
public A getAge() {
return age;
}
public void setAge(A age) {
this.age = age;
}
}
package chap08.ex09.inherit;
public class DetailInfo<N, A, H> extends BasicInfo<N, A> {
private H hobby;
public H getHobby() {
return hobby;
}
public void setHobby(H hobby) {
this.hobby = hobby;
}
}
package chap08.ex09.inherit;
public class Main {
public static void main(String[] args) {
DetailInfo<String, Integer, String> info = new DetailInfo<String, Integer, String>();
info.setName("홍길동");
info.setAge(25);
info.setHobby("게임");
String name = info.getName();
int age = info.getAge();
String hobby = info.getHobby();
System.out.println(name + "/" + age + "/" + hobby);
}
}