1. Object 타입
public class Box {
public Object content;
}
설계할 당시에 구체적인 타입이 지정이 안 됐을 때, 최상위 부모 클래스인 Object 나 Generic 타입으로 선언하는 방식을 주로 사용하게 된다.
Object 타입은 모든 클래스의 최상위 부모 클래스이기 때문에,
모든 객체는 부모 타입인 Object 로 자동 타입 변환이 되므로 어떤 객체든 대입이 가능하기 때문이다.
Object 타입으로 선언 시, 대입된 내용물의 타입을 모른다면, instanceof 연산자로 타입을 조사할 수는 있지만,
모든 종류의 클래스를 대상으로 조사할 수는 없다. 따라서, Object 타입으로 선언하는 것은 좋지 않다.
또한, Object 타입으로 선언할 시에는 나중에 자식 객체 타입에 메소드를 사용하고 싶을 경우,
강제로 타입을 변환해서 사용해야 한다. 강제 타입 변환이 빈번하게 일어난다면 성능이 좋지는 않다..
그렇다면, 어떻게 강제 타입 변환을 줄일까?
Object 타입으로 선언을 해버리면, 모든 자식들이 자신의 메소드를 사용할 때 강제로 타입 변환이 필요하게 되므로
애초에 Object 타입을 사용하지 않으면 된다.
이에, Generic 타입으로 선언을 한다면 강제 타입 변환을 줄일 수가 있다.
2. 제네릭(Generic) 이란?
결정되지 않은 타입을 파라미터로 처리하고, 객체를 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능을 말한다.
public class Box<T> {
public T content;
}
위와 같이, 결정되지 않은 타입을 T 라는 파라미터로 정의한 것이다.
여기서, <T> 는 T가 타입 파라미터임을 뜻하는 기호이고, T 대신 A 부터 Z 까지 어떤 알파벳을 사용해도 좋다.
타입 | 설명 |
<T> | Type |
<E> | Element |
<K> | Key |
<V> | Value |
<N> | Number |
보통 제네릭은 위와 같은 표의 타입을 사용해 많이 쓰인다.
Box<Integer> box = new Box<Integer>;
box.content = 100; // boxing
int content = box.content; // unboxing -> 강제 타입 변환 필요없이 100을 바로 얻을 수 있다.
위 코드처럼 타입 파라미터로 Integer 로 대체 시, 강제 타입 변환 필요 없이 자동으로 박싱과 언박싱이 이루어지기 때문에 값을 바로 얻을 수 있게 된다.
제네릭 타입은 실행하면서 T로 설정한 타입 파라미터에 객체를 생성할 때 사용할 타입이 바로 대체되기 때문에 Object 타입과 달리 따로 강제 타입 변환이 필요 없다.
따라서, Object 타입으로 선언하는 것보다 제네릭 타입으로 선언하는 게 더 좋다.
2.1 제네릭 타입 사용 시 주의사항
타입 파라미터를 대체하는 타입은 클래스 및 인터페이스이다.
[목차 2] 를 보면, 타입 파라미터 안에 <int> 가 아닌 <Integer>로 대체한 이유는 기본 타입은 타입 파라미터의 대체 타입이 될 수 없기 때문이다.
따라서, 타입 파라미터 안에는 기본 타입이 올 수 없고, 기본 타입의 wrapper class로 대체되어 사용된다.
또한, 제네릭 타입으로 선언을 했는데 구체적인 타입을 명시하지 않고 객체를 생성하게 된 경우에는
해당 타입은 Object로 간주하게 된다.
3. 제네릭 메소드 (Generic Method)
제네릭 메소드는 제네릭과 별개로 타입 파라미터를 갖고 있는 메소드를 말한다.
타입 파라미터가 메소드 선언부에 정의된다는 점에서 제네릭 타입과 차이가 있다.
public <A, B, ...> 리턴타입 메소드명(매개변수, ...) {...}
위와 같이, 제네릭 메소드는 리턴 타입 앞에 < > 기호를 추가하여 타입 파라미터를 정의한 다음에 리턴 타입과 매개변수 타입에서 사용할 수 있다.
public static <T> Box<T> boxing(T t) {...}
위 코드를 보면, boxing() 메소드는 타입 파라미터로 <T> 를 정의하고,
매개변수와 리턴타입에서 T 를 사용한다. 또한, 리턴 타입은 T 타입을 갖는 Box 객체이다.
Box<Integer> box1 = boxing(100); // (1)
Box<String> box2 = boxing("안녕하세요"); // (2)
타입 파라미터 T 는 매개값이 어떤 타입이냐에 따라 컴파일 과정에서 구체적인 타입으로 대체된다.
[(1) 코드]에서는 타입 파라미터가 Integer 타입으로 대체되어, Box <Integer>가 리턴되며,
[(2) 코드]에서는 타입 파라미터가 String 타입으로 대체되어, Box<String> 이 리턴되게 된다.