Java에서 제네릭이란?
제네릭(Generic)은 Java 5부터 도입되어, Java의 타입 안전성을 더욱 강화시켜주는 기능 중 하나입니다.
제네릭의 필요성
Java에서 컬렉션, 예를 들면 ArrayList
를 사용할 때, 우리는 다양한 타입의 객체를 저장할 수 있습니다. 그러나 아래와 같은 상황이 발생할 수 있습니다.
1
2
3
4
5
ArrayList list = new ArrayList();
list.add("string");
list.add(123);
String item = (String) list.get(1); // 오류! ClassCastException 발생
위의 코드에서 우리는 list
에 문자열과 정수를 동시에 넣었습니다. 따라서 값을 가져올 때 적절한 타입으로 형 변환을 해주어야 합니다. 그렇지 않으면 런타임에서 ClassCastException
이 발생하게 됩니다.
제네릭을 사용하면 이런 문제를 컴파일 시점에서 방지할 수 있습니다.
제네릭의 기본 구조
제네릭을 사용하면 컬렉션에 저장되는 타입을 지정해줄 수 있습니다.
1
2
3
ArrayList<String> list = new ArrayList<String>();
list.add("string");
// list.add(123); // 컴파일 오류!
이렇게 제네릭을 사용하면 list
에는 문자열만 추가될 수 있습니다. 다른 타입의 값을 추가하려고 하면 컴파일 시점에서 오류를 발견할 수 있습니다.
타입 파라미터
제네릭에서는 타입을 파라미터로 받아 사용합니다. 대표적으로 사용되는 타입 파라미터로는 T
, E
, K
, V
등이 있습니다.
T
: TypeE
: ElementK
: KeyV
: Value
1. T (Type)
1
2
3
4
5
6
7
8
9
10
11
public class GenericBox<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
위의 GenericBox
클래스는 어떤 타입의 값을 저장하고 가져올 수 있습니다. 사용 예는 다음과 같습니다.
1
2
3
4
5
6
7
GenericBox<String> box1 = new GenericBox<>();
box1.set("Hello");
String value = box1.get();
GenericBox<Integer> box2 = new GenericBox<>();
box2.set(123);
int num = box2.get();
2. E (Element)
컬렉션에서 주로 사용되는 타입입니다. List
나 Set
에서 항목의 타입을 표현할 때 사용됩니다.
1
2
3
List<E> list = new ArrayList<>();
list.add(element);
E firstElement = list.get(0);
3. K & V (Key & Value)
Map
에서 주로 사용되는 타입입니다. K
는 키의 타입, V
는 값의 타입을 나타냅니다.
1
2
3
Map<K, V> map = new HashMap<>();
map.put(key, value);
V retrievedValue = map.get(key);
String
을 키로, Integer
를 값으로 가지는 Map
의 예제는 다음과 같습니다.
1
2
3
Map<String, Integer> studentGrades = new HashMap<>();
studentGrades.put("John", 90);
Integer johnGrade = studentGrades.get("John");
제네릭의 장점
- 타입 안전성: 컴파일 시점에서 오류를 체크할 수 있으므로, 런타임 오류를 줄일 수 있습니다.
- 타입 체크 및 형 변환의 생략: 명시적인 형 변환 없이 코드를 작성할 수 있으므로, 코드가 더 간결해집니다.
마치며
Java의 제네릭은 코드의 타입 안전성을 높여주고, 간결하게 작성할 수 있게 도와줍니다. 복잡한 프로그램을 작성할 때, 제네릭의 이점을 활용하여 효과적인 코드를 작성하는 것이 좋습니다.