본문 바로가기

Java

[Java] 이것이 자바다 - 제네릭

제네릭이란?

제네릭이란 자바의 타입 안정성을 맡고 있으며 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 해결할 수 있게 도와준다. 또한 비제네릭 코드는 불필요한 타입 변환을 하기 때문에 프로그램 성능에 악영향을 미치는데 아래 예시와 같이 제네릭을 사용하면 List에 저장되는 요소를 String 타입으로 국한하기 때문에 타입 변환을 할 필요가 없어 프로그램 성능이 향상된다.

// 제네릭을 사용하지 않을 경우
List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0);
// 제네릭을 사용할 경우
List<String> list = new ArrayList<String>();
list.add("hello");
Stirng str = list.get(0);

클래스에서의 제네릭 사용

아래와 같은 클래스가 있다고 가정해보자

public class Box {
    private Object object;
    public void set(Object object) {
    	this.object = object;
    }
    public Object get() {
    	return obejct;
    }
}

Box 클래스의 필드 타입을 Object로 선언했는데 Object 클래스는 모든 자바 클래스의 최상위 부모 클래스이기 때문에 어떤 타입이든 담을 수 있다. 위 클래스에서도 set메소드로 모든 타입을 저장할 수 있게 했는데 문제는 get 메소드를 사용할 때 발생한다.

제네릭을 설명할때 제네릭을 사용하지 않으면 리스트에서 값을 조회하면서 타입 변환을 해줬어야 했는데 이 경우에도 마찬가지이다.

public class BoxExample {
    public static void main(String[] args) {
    	Box box = new Box();
        box.set("홍길동");
        String name = (String) box.get();
    }
}

위 코드에서 저장할때 String 타입으로 저장했지만 조회해올때 다시 String 타입으로 타입변환 해준 것을 확인할 수 있다. 이렇게 되면 저장할 때와 조회해올 때 모두 타입 변환이 일어나기 때문에 전체 프로그램에 악영향을 미칠 수 있다.

수정된 코드

public class Box<T> {
    private T t;
    public void set(T t) {
    	this.t = t;
    }
    public T get() {
    	return t;
    }
}
public class BoxExample {
    public static void main(String[] args) {
    	Box<String> box = new Box<String>();
        box.set("홍길동");
        String name = box.get();
    }
}

수정된 코드에서 타입 파라미터 T를 사용하여 Object 타입을 모두 T로 대체했다. 이렇게 제네릭 타입을 사용해서 구현하면 main 메소드에서 Box 객체를 생성할때 String 타입으로 선언할 수 있어 저장할 때와 조회해올 때 모두 타입 변환이 발생하지 않는다.

멀티 타입 파라미터

제네릭 타입은 두 개 이상의 멀티 타입 파라미터를 사용할 수 있는데, 각 타입 파라미터를 콤마(,)로 구분한다.

@Getter
@Setter
public class Product<T, M> {
    private T kind;
    private M model
}
Product<Tv, String> product = new Product<>();

메서드에서의 제네릭 사용

제네릭 메서드는 매개 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드를 의미한다. 리턴 타입 앞에 <> 기호를 추가하고 파라미터 타입을 지정한다.

public <T> Box<T> boxing(T t) { 
    Box<T> box = new Box<>();
    box.set(t);
    return box;
}