Back/Spring Java

제네릭(Generic) 문법

밍꿔 2019. 11. 25. 14:44


반응형

 

 

 

제네릭(Generic)은 코드블럭 내부에서 쓸 자료형을 외부에서 지정하는 기법. 여러가지 자료형을 허용하고 싶을 때 Object로 선언해버리면 깔끔하지만, 그렇게하면 원하지 않는 자료형이 입력되었을 때의 오류를 컴파일 시점에 잡아낼 수 없음.

 

* 장점

 

1. 컴파일 시 강한 타입 체크 가능.

 - 실행시 타입 에러가 나는 것보다 컴파일 시에 미리 타입을 강하게 체크해서 에러를 사전에 방지

 

 

2. 타입 변환(castring)을 제거.

 - 비제네릭 코드는 불필요하게 타입 변환을 하기 때문에 프로그램 성능에 악영향을 미친다.

 

List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0); // 타입 변환이 필요


List<String> list2 = new ArrayList<>();
list2.add("hello");
String str2 = list.get(0); // 불필요

 

 

* 종류

 

1. Generic Class

 클래스 내부에서 사용될 자료형을 지정하는 것이다. 대표적인 적용 예는 ArrayList가 있습니다.

 

class Foo<T> {
    private T t;
 
    public void set(T t) {
        this.t = t;
    }
 
    public T get() {
        return t;
    }
}

 

 

2. Generic Method

 굳이 클래스에 제네릭을 선언하지 않고, 메소드에만 제네릭을 선언하는 방법도 있다. 이때 주의해야할 점이 있는데, 파라미터 타입 또는 리턴타입에 제네릭을 선언했으면 메소드의 리턴타입 앞에도 똑같이 선언해 주어야 한다. 

 

class Koo {
    // 두개 이상의 파라미터에도 각각 제네릭을 설정할 수 있다.
    public <N1, N2> Integer exampleOne(N1 t, N2 e) {
        return (Integer)t + (Integer)e;
    }
 
    // 먼저 나왔던 Foo 클래스를 리턴타입으로 정의한 메소드
    public <String> Foo<String> exampleTwo() {
        return new Foo<>();
    }
}

 

 

3. Generic Interface

 제네릭 클래스와 비슷하다. 클래스들이 인터페이스를 조금 더 유연하게 구현(implement)할 수 있다.

 

interface Roo <T1, T2, T3> {
    T1 implementThis(T1 t1);
    T2 implementThis();
    T3 maintainGeneric(T3 t3);
}
 
// 제네릭에 어떤 자료형의 정의하느냐에 따라 유연하게 구현 가능.
class roo <String, Integer, T3> implements Roo<String,Integer,T3> {
 
    @Override
    public String implementThis(String s) {
        return s;
    }
 
    @Override
    public Integer implementThis() {
        return null;
    }
 
    // 이렇게 제네릭을 유지하는 방법도 있음.
    @Override
    public T3 maintainGeneric(T3 t3) {
        return null;
    }
}

 

 

 

* 활용

class Koo {
    public <N1, N2> Integer exampleOne(N1 t, N2 e) {
        // t와 e에 숫자가 아닌 것이 들어오면 오류 발생!!
        return (Integer)t + (Integer)e;
    }
}
 
public class Main {
    public static void main(String [] args) {
        Koo koo = new Koo();
        int result = koo.exampleOne("abc","efg");
        System.out.println(result);
    }
}

 

exampleOne 메소드에는 사실상 아무거나 들어올 수 있는 상황인데, 메소드 내부에서는 Integer로 강제 형변환하고 있다. 위 소스코드는 오류 없이 멀쩡하게 실행시킬 수 있지만, 실행하면 cannot be cast 오류 발생 하기 때문에 아래와 같이 수정 진행.

 

class Koo {
    public <N1 extends Integer, N2 extends Integer> Integer exampleOne(N1 t, N2 e) {
        return Integer.valueOf(t) + Integer.valueOf(e);
    }
}

 

 

* 와일드카드 타입(<?>, <? extends ..>, <? super ...>)

 

 - 제네릭타입<?> : 제한 없음 (모든 클래스나 인터페이스 타입이 올 수 있다)   

 - 제네릭타입<? extends 상위타입> : 상위 클래스 제한

 - 제네릭타입<? super 하위타입> : 하위 클래스 제한

 

 

* 기타 (제네릭에 쓰인 T, V, N등의 알파벳 대문자 의미)

E - Element

K - Key

N - Number

T - Type

V - Value

 

 

 

반응형

'Back > Spring Java' 카테고리의 다른 글

Spring Security Login  (2) 2019.12.18
가변인자 Varargs  (0) 2019.12.18
Lombok - @Slf4j  (0) 2019.11.25
Java8 null체크 시 Optional  (0) 2019.11.24
Lombok - @Builder, @Accessors 사용법  (0) 2019.11.19