본문 바로가기
☕Java/Java 기본

자바 지네릭

by 캔 2024. 5. 19.

지난번에 enum 설명에 이어서, enum과 마찬가지로 자바 1.5에서 등장한 지네릭에 대해서 이야기해보려고 한다.

 

지네릭은 클래스나 메서드에서 사용할 데이터 타입을 제한한다. 이렇게 함으로써 타입 안전성을 제공하고, 변수 사용 시에 타입 체크나 타입 캐스팅을 수행하지 않아도 되는 이점이 있다.

 

사용 방법

지네릭 클래스

지네릭 클래스는 클래스 이름 뒤에 "타입 변수 T"를 명시해 준다.

 

public class A<T> {
    T item;
    
    public T getItem() {
    	return item;
    }
    
    public void setItem(T item) {
    	this.item = item;
    }
}

 

A<String> a = new A<>();
a.setItem("abc");
String string = a.getItem();

 

객체 A 생성 시에 타입 변수 T가 String으로 결정돼 있으므로, getItem() 메서드를 호출할 때 String 타입으로 형 변환할 필요가 없다.

 

static 멤버에는 타입 변수 T를 사용할 수 없다. 객체 인스턴스화 전에는 타입을 알 수 없어 실행 초기에 스태틱 멤버를 적재할 수 없기 때문이다. 지네릭 타입 배열도 생성할 수 없으며, instanceof 연산자, new 연산자도 타입 변수 T를 피연산자로 사용할 수 없다.

 

타입 변수 제한하기

특정 클래스, 인터페이스의 자손들만 사용할 수 있도록 타입을 제한하려면 "<T extends Superclass>"와 와 같이 extends 예약어를 쓰면 된다. "<T extends Superclass1 & Superclass2>"처럼 여러 부모 클래스를 상속하는 타입으로 제한할 수도 있다.

 

static 메서드에 제네릭을 사용하거나 타입변수가 다른 메서드를 오버로딩하려면 와일드카드를 사용한다.

 

와일드카드를 사용하면 타입 변수에 어떠한 타입도 들어올 수 있다. "<?>"(<? extends Object>와 동일)처럼 쓰면, 모든 타입이 사용 가능하며, "<? extends Superclass>"처럼 쓰면 Superclass 자손 클래스는 모두 사용 가능하다. "<? super Subclass>"처럼 쓰면 Subclass의 조상 클래스만 사용 가능하다.

 

지네릭 메서드

지네릭 메서드는 접근 제한자와 리턴 타입 사이에 "타입변수 T"를 넣어 준다.

public <T> void methodA(T t) {}

public <T> static void methodB(T t) {} // static 메서드일 경우

 

지네릭 메서드의 타입 변수 T는 지네릭 클래스의 타입 변수 T와는 문자만 같을 뿐 전혀 별개의 것이다. 따라서, 메서드 스코프 내에서 사용되고 있는 타입 변수는 클래스의 타입변수와 다를 수 있다.

 

지네릭 메서드는 static 메서드에도 사용이 가능하다.

 

지네릭 타입 캐스팅

지네릭 타입과 원시 타입(넌지네릭 타입) 간에는, 경고가 발생하지만 타입 캐스팅이 가능하다. ex) A<T> ↔ A

반면, 지네릭 타입 간에는 타입 캐스팅 불가능하다. ex) A<T> ↔ A<U>

지네릭 타입과 상속 클래스 제한 제네릭 타입 간에는 타입 캐스팅이 가능하다. ex) A<T> ↔ A<T extends Superclass>

 

컴파일 시 지네릭 타입 제거

자바 컴파일러는 이전 버전 소스 코드와의 호환을 위해 컴파일 시에 지네릭을 제거하여 클래스 파일을 만든다.

 

지네릭 타입을 사용할 수 있는 곳에는 원시 타입을 허용하더라도 이제는 반드시 지네릭 타입을 사용하자. 그렇게 해야 자바 언어 자체의 타입 안전성을 향상해 주고 신규 개발자들도 이런 타입 안전성을 누릴 수 있을 테니 말이다.