출처 : http://palpit.tistory.com/665
제네릭 타입 ( class<T> , interface<T> )
제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말합니다.
제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 "<>"부호가 붙고, 사이에 타입 파라미터가 위치합니다.
아래 코드에서 타입 파라미터의 이름은 T 입니다.
public class className<T> { ... }
public interface interfaceName<T> { ... }
타입 파라미터는 변수명과 동일한 규칙에 따라 작성할 수 있지만, 일반적으로 대문자 알파벳 한 글자로 표현합니다.
제네릭 타입을 실제 코드에서 사용하려면 타입 파라미터에 구체적인 타입을 지정해야 합니다.
그럼 제네릭 타입을 왜 쓸까요?
public class Box {
private Object obj;
public void set(Object obj) {
this.obj = obj;
}
public Object get() { return this.obj; }
}
Box 클래스의 필드 타입이 Object 인데, Object 타입으로 선언한 이유는 필드에 모든 종류의 객체를 저장하고 싶기 때문입니다.
Object 클래스는 모든 자바 클래스의 최상위 클래스입니다.
따라서 자식 객체는 부모 타입에 대입할 수 있다는 성질 때문에 모든 자바 객체는 Object 타입으로 자동 타입 변환되어 저장됩니다.
Object object = 모든 객체.
set() 메소드는 파라미터 타입으로 Object 를 사용함으로써 파라미터로 자바의 모든 객체를 받을 수 있게 했고, 받은 파라미터를 Object 필드에 저장시킵니다.
반대로 get() 메소드는 Object 필드에 저장된 객체를 Object 타입으로 리턴합니다.
만약 필드에 저장된 원래 타입의 객체를 얻으려면 다음과 같이 강제 타입 변환을 해야 합니다.
Box box = new Box();
box.set("HI");
String str = (String)box.get();
******* Example
package study;
/*
* 제네릭 사용 example
*/
class Box {
private Object object;
public Box() {}
public Box(Object object) {
this.object = object;
}
public Object getObject() {
return this.object;
}
public void setObject(Object object) {
this.object = object;
}
}
class Apple { }
public class HomeStudyGeneric {
public static void main(String[] args) {
Box box = new Box();
box.setObject("Jack");
String name = (String)box.getObject();
System.out.println(name);
box.setObject(new Apple());
Apple apple = (Apple)box.getObject();
System.out.println(apple.getClass().getName());
}
}
이와 같이 Object 타입을 사용하면 모든 종류의 자바 객체를 저장할 수 있다는 장점은 있지만, 저장할 때 타입 변환이 발생하고 읽어올 때도 타입 변환이 발생합니다.
이러한 타입 변환이 빈번해지면 전체 프로그램 성능에 좋지 못한 결과를 가져올 수 있습니다.
그렇다면 모든 종류의 객체를 저장하면서 타입 변환이 발생하지 않도록 하는 방법이 없을까요 ???
해결책은 제네릭 입니다!!
class Box<T> {
private T t;
public Box() {}
public T getObject() {
return this.t;
}
public void setObject(T t) {
this.t = t;
}
}
타입 파라미터 T를 사용해서 Object 타입을 모두 T로 대체했습니다. T는 Box 클래스로 객체를 생성할 때 구체적인 타입으로 변경됩니다.
예를 들어, 다음과 같이 Box 객체를 생성했다고 가정해보자.
Box<String> box = new Box<String>();
타입 파라미터 T는 String 타입으로 변경되어 Box 클래스의 내부는 아래와 같이 자동으로 재구성 됩니다.
class Box<String> {
private String t;
public Box() {}
public String getObject() {
return this.t;
}
public void setObject(String t) {
this.t = t;
}
}
필드 타입이 String 으로 변경되었고, set() 메소드도 String 타입만 파라미터로 받을 수 있게 변경 되었습니다.
다음은 위 예제를 제네릭을 적용시켜서 수정하였습니다.
class Box<T> {
private T t;
public Box() {}
public T get() {
return this.t;
}
public void set(T t) {
this.t = t;
}
}
class Apple { }
public class HomeStudyGeneric {
public static void main(String[] args) {
Box<String> stringBox = new Box<String>();
stringBox.set("hi");
String str = stringBox.get();
System.out.println(str);
Box<Integer> integerBox = new Box<Integer>();
integerBox.set(11);
int value = integerBox.get();
System.out.println(value);
}
}