제네릭(Generics)은 자바에서 클래스 또는 인터페이스를 정의할 때 타입(Type)을 일반화(일반화된 타입 파라미터)하여 코드를 구현하는 기법입니다. 즉, 클래스 또는 인터페이스를 정의할 때, 타입을 일반적으로 표현하고, 이를 실제로 사용할 때 구체적인 타입으로 결정합니다.
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
public class Main {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<>();
Box<String> stringBox = new Box<>();
integerBox.set(10);
stringBox.set("Hello World");
int intValue = integerBox.get();
String strValue = stringBox.get();
System.out.println(intValue);
System.out.println(strValue);
}
}
위의 예시에서는 Box 클래스를 정의할 때, 제네릭 타입 파라미터 T를 사용합니다. 이 T는 Box 클래스를 실제로 사용할 때, 구체적인 타입으로 대체됩니다. Main 클래스에서는 Box 클래스를 Integer와 String 타입으로 사용합니다.
integerBox와 stringBox 객체에 각각 값을 저장한 후, intValue와 strValue 변수에 값을 가져올 때 타입 변환이 필요하지 않습니다. 이는 제네릭을 사용함으로써 코드의 가독성을 높이는 데 도움을 줍니다.
컬렉션 클래스는 데이터를 저장하고 관리하는 데 사용되는 클래스입니다. 자바 컬렉션 프레임워크에는 List, Set, Queue, Map 등의 인터페이스와 그에 대한 구현체가 포함되어 있습니다.
이러한 컬렉션 클래스에서 제네릭을 사용하는 이유는 다음과 같습니다.
제네릭을 사용하면 컬렉션 내부에 저장된 요소의 타입을 컴파일 시점에 체크할 수 있습니다. 이를 통해 잘못된 타입의 객체가 저장되는 것을 방지하고, 코드 실행 시 예외를 던지지 않도록 합니다. 이는 프로그램의 안정성을 높여주는데 중요한 역할을 합니다.
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add(1); // 컴파일 에러 발생
for(String name : names) {
System.out.println(name);
}
제네릭을 사용하지 않은 컬렉션 클래스를 사용할 경우, 컬렉션 내부에 저장된 요소를 꺼내서 사용할 때마다 타입 변환을 해주어야 합니다. 이는 코드의 가독성을 떨어뜨리고, 잘못된 타입 변환으로 인한 런타임 오류가 발생할 수 있습니다. 제네릭을 사용하면 이러한 타입 변환을 제거할 수 있습니다.
List names = new ArrayList();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add(1); // String만 추가할 수 있도록 하지 않았기 때문에, 잘못된 타입이 추가될 수 있습니다.
for(Object name : names) {
String str = (String) name; // 타입 변환 필요
System.out.println(str);
}