제네릭이란?
자바에서 제네릭(generic)이란 데이터 타입(data type)을 일반화(generalize)한다는 것을 의미합니다.
제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법입니다.
이렇게 컴파일 시에 미리 타입 검사(type check)를 수행하면 다음과 같은 장점이 있습니다.
- 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있습니다.
- 반환값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있습니다.
그렇다면 제네릭은 어떻게 사용해야 할까요? 그전에 제네릭 이전의 선언을 보겠습니다.
class BasketString {private String item; ...}
class BasketInteger {private integer item; ...}
class BasketChar {private Char item; ...}
class BasketDouble {private Double item; ...}
위 예제를 보면 네 클래스는 모두 같은 명칭의 변수를 사용하고 있지만, 각 타입별로 별도의 클래스를 만들어 주었습니다.
하지만 아래의 예제와 같이 제네릭을 사용하면 단 하나의 Basket 클래스만으로 모든 타입의 데이터를 저장할 수 있는 인스턴스를 만들 수 있습니다.
Class Basket<T> {private T item; ...}
클래스 옆의 <T>, 타입 매개변수를 이용하여 코드의 가독성이 좋아진 모습을 볼 수 있습니다.
위의 Basket 클래스는 다음과 같이 인스턴스 화 할 수 있습니다.
Basket<String> basket = new Basket<String>("낚시대");
// Basket<String> basket = new Basket<>("낚시대");
위의 예제 코드에서 보듯이, 제네릭은 클래스나 메서드의 코드를 작성할 때, 타입을 구체적으로 지정하는 것이 아니라, 추후 지정할 수 있도록 하는 기능을 제공합니다.
제네릭 클래스
제네릭이 사용된 클래스를 제네릭 클래스라고합니다. 아래의 예제를 함께 보도록 하겠습니다.
class Basket <T> {
private T item;
public Basket(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
위의 예제 코드에서, T를 타입 매개변수라 하였습니다, T와 같이 꺽쇠 안에 넣어 클래스 이름 옆에 작성해 줌으로써 클래스 내부에서 사용할 타입 매개변수를 선언할 수 있습니다.
제네릭 타입은 두개 이상의 멀티 타입 매개변수를 사용할 수 있습니다.
이 경우 각각의 타입 매개변수를 , (콤마)로 구분합니다.
public class Product<T, M> {
private T kind;
private T model;
public T getKind() {
return kind;
}
public T getModel() {
return model;
}
public void setKind(T kind) {
this.kind = kind;
}
public void setModel(T model) {
this.model = model;
}
}
보편적으로 사용되는 매개 변수의 이름과 의미는 다음과 같습니다.
T | TYPE |
V | Value |
N | Number |
K | Key |
E | Element |
제네릭 클래스 사용시 주의할 점
제네릭 클래스는 아래 예제 코드와 같이 클래스 변수에는 타입 매개변수를 사용할 수 없습니다
class Basket<T> {
private T item1;
static T item1; // error
}
클래스 변수는 모든 인스턴스가 공유하는 변수이지만 제네릭 클래스는 인스턴스 별로 다른 타입의 변수를 갖기 위해 사용하는 것이기 때문에 클래스 변수는 제네릭 클래스에서는 사용할 수 없습니다.
제네릭 메서드
클래스 내부의 특정 메서드만 제네릭으로 선언할 수 있습니다. 이를 제네릭 메서드라고 합니다.
제네릭 메서드의 선언은 아래의 예제 코드와 같이 할 수 있습니다.
class Basket {
pulbic <T> void add(T element){
...
}
}
제네릭 메서드 타입 매개변수는 제네릭 클래스 타입의 매개변수와 별개의 것입니다.
class Basket<T> {
...
public <T> void add (T element){
// 클래스의 매개변수 T와
// 메서드의 T는 서로 다르다
...
}
}
위 매개변수가 서로 다른 이유는 제네릭 클래스는 인스턴스화할 때 타입이 지정되며, 제네릭 메서드는 메서드가 호출될 때 타입이 지정되기 때문입니다.
또한, 제네릭 메서드는 제네릭 클래스와는 다르게 static 수식자 뒤에 사용될 수 있습니다.
class Basket {
...
static <T> int setPrice(T element) {
...
}
}
와일드카드
와일드카드는 타입 매개 변수를 어떠한 타입으로든 사용할 수 있습니다.
입란 적으로 와일드카드는 extends와 super 키워드를 조합하여 사용합니다.
<? extends T> // T와 T를 상속받는 하위 클래스 타입만 타입 매개 변수로 받을 수 있음
<? super T> // T와 T의 상위 클래스만 타입 매개 변수로 받을 수 잇음
이 외 extends와 super 키워드를 조합하지 않은 와일드카드 <?>는 <? extends Object>와 같습니다.
Reference
코드 스테이츠
'JAVA' 카테고리의 다른 글
[JAVA] 컬렉션 프레임워크(Collection Framework) - List <E> (2) (0) | 2023.03.09 |
---|---|
[JAVA] 컬렉션 프레임워크(Collection Framework) (1) (0) | 2023.03.09 |
[JAVA] 예외 처리(Exception Handling) (0) | 2023.03.08 |
[JAVA] 열거형(enum) (0) | 2023.03.06 |
[JAVA] Windows 개발 환경에서 자바 설치 및 개발 환경 세팅 (0) | 2023.02.20 |