PROGRAMMING LANGUAGE/자바

제네릭의 사용 이유와 종류

JC0 2023. 12. 28. 23:51

개요

자바 5부터 제네릭타입이 새로 추가되었다. 제네릭 타입을 이용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있게 되었다.

제네릭은 클래스와 인터페이스, 메소드를 정의할 때 타입을 파라미터로 사용할 수 있다.

 

제네릭을 사용하는 이유

컴파일 시 강한 타입 체크를 할 수 있다.

자바 컴파일러는 코드에서 잘못 사용된 타입 때문에 발생하는 문제점을 제거하기 위해서 제네릭 코드에 대해 강한 타입 체크를 한다. 

런타임 에러보다는 컴파일 에러가 좋다! 

런타임 에러는 프로그램 실행 중에 에러가 나는것이다.  운영중인 애플리케이션을 수정해야 하기 때문에

 그것보다는 컴파일 에러가 나는 것이 개발중에 에러를 고칠 수 있다는 장점이 있다.

 

List list = new ArrayList();
list.add("hello");
String str = (String)list.get(0); 
// 타입 변환을 해야한다.

List<String< list = new ArrayList<String>();
list.add("hello");
String str = list.get(0);
// 타입 변환을 하지 않는다.

 

 

제네릭 타입(class<T>, interface<T>)

제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다. 제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 "<>" 부호가 붙고, 사이에 타입 파라미터가 위치한다. 아래 코드에서 타입 파라미터의 이름은 T이다.

public class 클래스명<T>{}
public interface 인터페이스명<T>{}
// 선언 방식

 

Object를 이용한 타입변환과 제네릭을 사용한 코드의 차이

먼저 모든 클래스의 부모인 object 클래스를 이용하여 저장하고 데이터를 꺼내오는 코드이다.

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

Box box = new Box();
box.set("hello");  
String str = (String)box.get();
// String 타입을 object 타입으로 자동 변환하여 저장
// object 타입을 String 타입으로 강제 변환하여 꺼내옴

 

다음은 제네릭을 적용한 예시이다.

public class Box<T> {
	private T t;
    public T get() { return t; }
    public void set(T t) { this.t = t; }
}
// 제네릭 타입 사용

Box<String> box = new Box<String>();
// 제네릭에 String 적용

public class Box<String> {
	private String t;
    public void set(String t) { this.t = t; }
    public String get() { return t; }
}
// T타입 -> String타입 적용

제네릭을 이용하면 강제 타입 변환을 하지 않아도 된다.

 

멀티 타입 파라미터(class<K,V,...>, interface<K,V,...>)

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

// Product.java
public class Product<T,M> {
	private T kind;
    private M model;
    
    public T getKind() { return this.kind; }
    public M getModel() { return this.model; }
    
    public void setKind(T kind) { this.kind = kind; }
    public void setModel(M model) { this.model = model; }
}

// ProductExample.java
public class ProductExample {
	public static void main(String[] args){
    	product<Tv, String> product1 = new Product<Tv, String>();
        product1.setKind(new Tv());
        product1.setModel("스마트Tv");
        Tv tv = product1.getKind();
        String tvModel = product1.getModel();
}

// kind변수와 관련 메서드에는 Tv타입이 -> T타입에 적용된다.
// model변수와 관련 메서드에는 String타입이 -> M타입에 적용된다.

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

코드에서 ?를 일반적으로 와일드카드(wildcard)라고 부른다.

제네릭타입<?> 모든 클래스나 인터페이스 타입이 올 수 있다.

제네릭타입<? extends 상위타입> 자기 자신과 자식타입이 올 수 있다.

제네릭타입<? super 하위타입> 자기 자신과 부모타입이 올 수 있다.