제네릭은 무엇이고 어떻게 사용할까?
제네릭 (Generic)
--
제네릭은
다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에서
컴파일 시에 타입을 체크해 주는 기능으로
클래스, 인터페이스, 메서드에서 다양한 타입을 처리할 수 있도록 만들어준다.
간단하게 설명하면
원래 클래스에서 사용할 타입은 코드 작성할 때 명시해줘야 하지만
제네릭을 사용하면 사용할 때 외부에서 원하는 타입으로 지정하여 유동적으로 사용할 수 있다.
그래서 제네릭을 사용하면
컴파일 시의 타입을 검증할 수 있어서 코드의 안정성과 재사용성을 높일 수 있다.
제네릭의 주요 목적
- 타입 안정성 : 잘못된 타입을 사용하는 오류를 컴파일 단계에서 발견
- 코드 재사용성 : 하나의 코드로 다양한 타입을 처리 가능
- 가독성 향상 : 명시적 캐스팅을 줄이고 코드의 명확성을 높임
--
제네릭 사용 방법
--
기존 클래스
class Box {
private Object item;
public void setItem(Object item) {
this.item = item;
}
public Object getItem() {
return item;
}
}
제네릭 사용한 클래스
class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
System.out.println(stringBox.getItem());
// Hello
Box<Integer> intBox = new Box<>();
intBox.setItem(123);
System.out.println(intBox.getItem());
// 123
제네릭을 사용하기 위해서는
클래스 옆에 <T>를 붙이고 제네릭 타입을 사용할 타입을 T로 동일하게 변경하면 된다.
그러면 T에 사용하고 싶은 타입을 사용하면 T로 선언된 모든 타입은 사용할 타입으로 모두 치환된다.
제네릭 용어
- Box<T> : 제네릭 클래스
- Box : 원시 타입 (일반 클래스)
- T : 타입 변수 or 타입 매개변수
Box<String> box = new Box<String>();
// 참조변수 T와 생성자 T는 동일해야 한다.
- 타입 매개변수에 타입을 지정하는 것 : 제네릭 타입 호출
- 지정된 타입 "String" : 매개변수화된 타입 (= 대입된 타입)
컴파일 후에는 Box<String>이 Box로 변경되어 사용된다.
즉, 실행하면 제네릭 타입은 제거되고 원래 원시 타입처럼 사용하게 된다.
이 말은
제네틱 타입이 Object로 대체되어 원시 타입처럼 변경되고,
사용하려던 타입(String)으로 타입 캐스팅이 자동으로 추가되어 사용하게 된다.
[컴파일 전]
Box<String> box = new Box<>();
box.setItem("Hello");
String item = box.getItme();
[컴파일 후]
Box box = new Box();
box.setItem("Hello");
String item = (String) box.getItem();
즉, 제네릭은 원래 Object 타입으로 사용하지만 실행 시점에서 지정한 타입으로 자동 캐스팅되도록 해주는 기능이라고 생각하면 된다.
제네릭을 사용하기 전에는
다양한 종류의 타입을 다루기 위해 Object타입을 많이 사용했지만,
이로 인해 형변환을 불가피했다.
하지만 제네릭으로 Object타입 대신 원하는 타입을 지정하여 사용할 수 있게 되었다.
<T>에서 T는 일반적으로 "Type"의 첫 글자를 따온 것이지만 꼭 T로 사용할 필요는 없다.
즉, 아무 이름으로 사용할 수 있지만 알아보기 편하게 약속한 문자를 일반적으로 사용한다.
여러 제네릭 타입을 사용하는 방법은 콤마','를 구분자로 나열하여 사용하면 된다.
public class Triple<K, V, S> {
private K key;
private V value;
private S description;
public Triple(K key, V value, S description) {
this.key = key;
this.value = value;
this.description = description;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public S getDescription() {
return description;
}
}
Triple<String, Integer, String> triple = new Triple<>("Age", 25, "years");
System.out.println(triple.getKey()); // Age
System.out.println(triple.getValue()); // 25
System.out.println(triple.getDescription()); // years
--
제네릭의 제한 사항
--
1. 기본형은 사용 불가
int, double 등의 기본 타입은 사용할 수 없으므로 래퍼 클래스를 사용해야 한다.
2. 런타임 시 타입 소거
제네릭 타입은 컴파일 타임에만 사용되고, 런타임에는 제거된다.
제네릭은 "컴파일 타임"에만 타입을 확인하며, "런타임"에는 해당 타입 정보가 제거된다.
즉, 제네릭을 사용하더라도 JVM은 실제로 모든 타입을 Object로 처리한다.
Object 타입을 지정한 타입으로 자동 캐스팅하여 사용하는 것뿐이다.
3. static (필드, 메서드 등)에서는 사용 불가
public class Box<T> {
private T value;
public static T createValue() { // 컴파일 에러
return new T(); // 제네릭 타입 T 사용 불가
}
}
T는 Box 객체를 생성할 때 결정된다.
하지만 static은 객체 생성과 상관없이 바로 사용할 수 있어야 하는데
static 메서드에서는 해당 정보를 알 수 없으므로 에러발생 한다.
public class GenericExample {
public static <T> void print(T value) {
System.out.println(value);
}
}
// 사용 예시
GenericExample.print("Hello"); // 출력: Hello
GenericExample.print(123); // 출력: 123
메서드 자체에서 제네릭 타입 <T>를 선언했기 때문에
static 메서드에서도 제네릭을 사용할 수 있게 된다.
--
와일드카드 <?>
--
와일드카드는
제네릭 타입을 보다 유연하게 사용할 수 있도록 해주는 문법으로
"?"기호로 표현되며, 주로 제네릭 타입의 범위를 지정하거나 불특정한 제네릭 타입을 허용할 때 사용된다.
<?> 예시
public void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
list.add("Hello"); // 컴파일 에러
list.add(123); // 컴파일 에러
<? extends T> 예시
public void printNumbers(List<? extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
<? super T> 예시
public static void addValues(List<? super Integer> list) {
list.add(10);
list.add(20);
}
정리
- <?> : 타입에 관계없이 읽기 전용일 때 사용 (제약 없는 읽기 전용)
- <? extends T> : 데이터를 읽기만 할 때 사용 (읽기 전용)
- <? super T> : 데이터를 쓰기만 할 때 사용 (쓰기 전용)
--
'Language > Java' 카테고리의 다른 글
스레드의 상태 종류 & 제어 (0) | 2025.01.08 |
---|---|
스레드 (Thread) (0) | 2024.12.29 |
Arrays 클래스에서 제공하는 메서드 (0) | 2024.12.25 |
Iterator & ListIterator (0) | 2024.12.21 |
[Java] Stack과 Queue 사용하기 (1) | 2024.12.20 |