본문으로 바로가기

1. 제네릭(Generic)

  • 제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다.
  • 제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 "<>" 부호가 붙고, 사이에 타입 파라미터가 위치한다. <T>
  • 타입 파라미터는 일반적으로 대문자 알파벳 한 글자로 표현합니다.
  • 제네릭을 사용하면 특정 클래스나 인터페이스에 다양한 타입으로 사용 및 저장할 필요가 있을 경우 편리합니다. (재활용 가능)  
  • 제네릭을 통해 타입을 지정하게 됨으로써 타입 변환을 줄이게 되어 프로그램 성능에 유리합니다.
  • 제네릭은 자바의 여러 기능에서 사용되고 있으므로 자바를 잘 활용하기 위해서는 무조건 이해해야 합니다. (Collection, Stream API, Lambda)

 

[제네릭 형태]

public class 클래스명<T> { 
	... 
}

public interface 인터페이스명<T> { 
	... 
}

 

[제네릭 예시]

public interface List<E> extends Collection<E> {
    boolean add(E e);
    E get(int index);
    E set(int index, E element);
    E remove(int index);
    // ...
}
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {

    public boolean add(E e) {
        //...        
    }
    
    public E get(int index) {
        //...    
    }
    
    public E set(int index, E element) {
        //...
    }
    
    public E remove(int index) {
        //...
    }    
}

 

2. 제네릭 타입 사용법(Example)

제네릭 타입을 이용하여 API Response(Response DTO)를 만들 때 활용합니다.

다음과 같은 API를 만들어야 한다고 가정할 때,

API 예시

Json의 구조(key 값)의 형태가 같습니다. 그러나 data 안에 들어가는 데이터가 여러 경우일 경우 제네릭을 활용해 노가다를 하지 않고 다음과 같이 편하게 구현할 수 있습니다. (공통부분 활용)

@GetMapping(value = "/stock/info")
public Response info() {
    return new Response(200, "OK", new ResponseStockInfo("Apple Inc","AAPL","NASDAQ", 167.30));
}

@GetMapping(value = "/stock/list")
public Response list() {
    List<ResponseStockList> stockLists =  new ArrayList<>();
    stockLists.add(new ResponseStockList("Apple Inc", "AAPL"));
    stockLists.add(new ResponseStockList("Microsoft Corporation", "MSFT"));

    return new Response(200, "OK", stockLists);
}

json의 data 부분은 T(제네릭 타입)을 이용하여 여러 타입을 지정할 수 있습니다. 

//==Response DTO==//
@Data
@AllArgsConstructor
static class Response<T> {
    private Integer code;
    private String msg;
    private T data;
}

//==Response DTO==//
@Data
@AllArgsConstructor
static class ResponseStockInfo {
    private String companyName;
    private String ticker;
    private String market;
    private Double price;
}

//==Response DTO==//
@Data
@AllArgsConstructor
static class ResponseStockList {
    private String companyName;
    private String ticker;
}

 

3. 멀티 타입 파라미터 사용법(Example)

  • 제네릭 타입은 두 개 이상의 멀티 타입 파라미터를 지원합니다.
  • 콤마를 이용하여 구분합니다.

 

[멀티 타입 파라미터 형태]

public class 클래스명<T, V> { 
	... 
}

public interface 인터페이스명<T, V> { 
	... 
}

 

[멀티 타입 파라미터 예시]

public interface Map<K, V> {

    V get(Object key);
    V put(K key, V value);
    V remove(Object key);
    // ...
}
public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    
    public V get(Object key) {
        // ...
    }
    
    public V put(K key, V value) {
        // ...
    }
    
    public V remove(Object key) {
        // ...
    }
}

 

4. 자바 7 이후의 제네릭 변화

[자바 6 이전]

  • 제네릭 타입 변수 선언과 객체 생성을 동시에 할 경우 코드가 중복되어 복잡해 보일 수 있습니다.
// 자바 6 이전
List<String> list = new ArrayList<String>();
Map<String, String> map = new HashMap<String, String>();

 

[자바 7 이후]

  • 제네릭 타입 파라미터의 중복 기술을 줄이기 위해 <>를 제공합니다.
  • 자바 컴파일러가 타입 파라미터를 유추해서 자동으로 설정해줍니다.
// 자바 7 이후
List<String> list = new ArrayList<>();
Map<String, String> map = new HashMap<>();