제네릭 메서드

반응형
728x90
반응형

제네릭

public interface Comparable<T> {
    int compareTo(T o);
}

 

위 Comparable의 메소드는 Comparable, Comparable 등을 구현할 수 있다. 타입을 명시하여 String, Integer 각 타입별 중복된 메소드를 생성할 필요없이 제네릭을 사용하여 중복된 코드를 공통으로 묶을 수 있고, 타입에 자유로워질 수 있다. 형변환의 에러는 컴파일시에 나타나지 않고 런타임 오류로 발생하는데, 이 에러를 컴파일시에 발견할 수 있다는 장점도 제네릭의 큰 장점이다.

 

제네릭은 static 변수에 사용이 불가능하다.
static 변수는 클래스 변수로, 모든 인스턴스에게 공유되는 변수이다. static 변수에 제네릭을 사용하게되면 모든 인스턴스에게 공유되는 변수가 경우에 따라 타입이 다르다는 말인데, 이는 말이 안된다.

 

 

 

제네릭 메서드 사용

제네릭으로 메서드를 만들 수 있다. 우선, 아래 예제를 보자.

public static Set union(Set s1, Set s2) {
    Set result = new HashSet(s1);
    result.addAll(s2);
    
    return result;
}

 

위 예제는 컴파일은 정상적으로 되지만, warning이 발생한다. 발생하는 이유는 타입이 명시되지 않았기 때문이다. 타입을 안전하게 만들어야하는데, 그러기 위해서는 원소 타입을 타입 매개변수로 명시하고 메서드 안에서도 이 타입 매개변수만 사용하게 수정하면 된다.

public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
    Set<E> result = new HashSet(s1);
    result.addAll(s2);
    
    return result;
}

 

위처럼 변경하면 기존에 존재했던 warning이 사라진다. 위 메소드를 사용하는 코드를 보자.

public static void main(String[] args) {
    Set<String> guys = Set.of("T", "E", "S", "T");
}

 

union 메소드는 매개변수로 넘어오는 모든 집합의 타입이 같아야한다. 이런 경우에는 아래처럼 와일드카드 타입을 사용하여 좀더 유연하게 개선할 수 있다. 이를 한정적 타입 매개변수(Bound Type Parameter)라고 하는데, 제네릭으로 사용될 타입 파라미터의 범위를 제한하는 것이다. 모든 타입의 매개변수를 가능하도록 하는것 보다는 아래처럼 필요한 제한을 두는것도 좋다. 아래 코드는 E 클래스를 상속하는 타입만 올 수 있도록 제한을 두었다.

public static <? extends E> Set<? extends E> union(Set<? extends E> s1, Set<? extends E> s2) {
    Set<? extends E> result = new HashSet(s1);
    result.addAll(s2);
    
    return result;
}

 

또는 아래와 같은 코드가 될 수도 있다. 아래 코드는 E 클래스의 상위클래스만 타입으로 가지도록 제한을 두었다.

public static <? super E> Set<? super E> union(Set<? super E> s1, Set<? super E> s2) {
    Set<? super E> result = new HashSet(s1);
    result.addAll(s2);
    
    return result;
}

 

 

 

제네릭 싱글턴 팩터리

불변 객체를 여러 타입으로 활용할 수 있게 만들어야할 경우가 있다. 이런 경우에도 제네릭을 사용하면, 하나의 객체를 어떤 타입으로든 매개변수화 할 수 있는 장점이 생긴다. 하지만 이렇게 하려면 요청한 타입 매개변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩터리를 만들어야한다. 이 패턴을 제네릭 싱글턴 팩터리 라고 한다.

 

private static UnaryOperator<Object> IDENTITY_FN = (t) -> t;

@SuppressWarnings("unchecked")
public static <T> UnaryOperator<T> identityFunction() {
    return (UnaryOperator<T>) IDENTITY_FN;
}

 

제네릭 싱글턴 팩터리 패턴을 구현해보았다. 불변 객체인 IDENTITY_FN의 타입에 제한이 없고 형 변환을 해주는 메소드를 생성했다. 그런데 여기서 IDENTUTY_FN을 UnaryOperator<T>로 형변환하면 비검사 형변환 경고가 발생한다. T가 어떤 타입이든 UnaryOperator<Object>는 UnaryOperator<T>가 아니기 때문에 발생한다.

 

 

 

마치며

설명보다 예제 위주의 포스팅이였지만, 제네릭에 관련해서는 예제로 이해하는게 더 빠르다고 생각한다. 클라이언트에서 입력 매개변수와 반환값을 명시적으로 형변환해야 하는 메서드 보다 제네릭 메서드가 더 안전하다. 메서드도 형변환 없이 사용할 수 있는 편이 좋고, 제네릭 메서드를 사용하면 이를 가능하게할 수 있다. 형변환이 필요한 메서드는 제네릭으로 만드는게 좋고, 제네릭을 사용하여 타입의 제한을 제거하고 중복되는 코드를 줄이는것이 좋다.

 

반응형

'Coding > Java' 카테고리의 다른 글

자바8의 default 메서드 등장  (0) 2020.11.06
의존 객체 주입의 사용 이유  (0) 2020.11.06
숫자형 스트림  (0) 2020.11.06
싱글턴 패턴  (0) 2020.11.06
스트림 연산  (0) 2020.11.06

Designed by JB FACTORY