제네릭 타입을 사용하는 이유는 잘못된 타입선언으로 인한 문제를 컴파일 과정에서 예방할 수 있기 때문이다.
제네릭 타입은 컴파일 시에 미리 타입을 체크할수 있어서 미리 에러를 사전에 방지하고, 타입 제한이 가능하여 요소를 찾아올 때, 타입 변환을 할 필요가 없어 프로그램 성능을 향상시킬 수 있다.
public class Bag<T> {
T thing;
public Bag(T thing){
this.thing = thing;
}
}
Bag<Book> bag = new Bag<>(new Book());
Bag<Pencil> bag2 = new Bag<>(new Pencil());
Bag<Pen> bag3 = new Bag<>(new Pen());
어떤 한 특정 객체를 상속받는 객체들만 Generic 타입으로 표시할 때, Generic 타입 뒤에 extends를 붙여서 사용한다.
class Book extends Solid{ }
class Pencil extends Solid{ }
class Pen extends Solid{ }
class Coke extends Liquid{ }
class Coffee extends Liquid{ }
Solid를 상속받는 객체만
public class Bag<T extends Solid> {
T thing;
public Bag(T thing){
this.thing = thing;
}
}
Liquid를 상속받는 객체만
public class Bag<T extends Liquid> {
T thing;
public Bag(T thing){
this.thing = thing;
}
}
제네릭 타입을 사용하는 객체를 변수로 받는 객체에서는 여러 타입으로 변수를 받기 때문에 한가지 타입으로만 선언할 수 없다. 그런 경우에는 와일드 카드, ?로 제네릭 타입을 지정해서 사용한다.
public clas Box{
ArrayList<Bag<?>> list = null;
public Box(){
list = new ArrayList<>();
}
public void put(Bag<?> bag){
list.add(bag);
}
public static void main(String[] args){
Bag<Book> bag = new Bag<>(new Book());
Box box = new Box();
box.put(bag);
Bag<Pen> bag2 = new Bag<>(new Pen());
box.put(bag2);
}
}
public class Bag<T, N> {
private T thing;
private N name;
public T getThing(){
return thing;
}
public void setThing(T thing){
this.thing = thing;
}
public N getName(){
return name;
}
public void setName(N name){
this.name = name;
}
}
public static void main(String[] args){
Bag<Book, String> bag = new Bag<>();
bag.setThing(new Book());
bag.setName("영어");
Bag<Pen, String> bag2 = new Bag<>();
bag2.setThing(new Pen());
bag2.setName("모나미");
}
매개 변수와 리턴 값의 타입이 제네릭으로 선언된 메소드
선언
public <타입 파라미터...> 리턴타입 메소드명(매개 변수, ...){ }
호출
- 리턴타입 변수 = <구체적인 타입> 메소드명(매개 값);
- 리턴타입 변수 = 메소드명(매개값);
public class Box{
public static <T> Bag<T> put(T thing){
Bag<T> bag = new Bag<T>;
bag.setThing(thing);
return bag;
}
}
public static void main(String[] args){
Bag<Book> bag = Util.<Book>put(new Book());
Bag<Pen> bag2 = Util.<Pen>put(new Pen());
}
메소드를 호출할 때, 인자값의 길이를 동적으로 조정하는 방법이다.
public void sum(int ... arg){
int result = 0;
for(int value : arg){
result += value;
}
System.out.println("합계 :"+result);
}
public static void main(String[] args){
Test test = new Test();
test.sum(10,20,30); // 결과값 = 60
test.sum(1,2,3,4,5,6,7); // 결과값 = 28
}
제네릭 타입 파라미터를 갖는 객체를 상속받는 객체는 항상 부모객체와 같은 타입 파라미터를 제네릭으로 갖고있어야 한다.