IT·테크/개발

Java 제네릭(Generic) — 캐스팅을 없애고 타입 검사를 컴파일 단계로 옮기기

레루루 2026. 7. 25. 20:00
반응형

Java 제네릭(Generic) — 캐스팅을 없애고 타입 검사를 컴파일 단계로 옮기기

이 글은 2022년 5월 기준 기록입니다.

 

Java는 부모 타입이 자식 타입을 모두 담을 수 있도록 함으로써 다형성을 구현합니다. 편리한 성질이지만 대가가 있습니다.

다형성은 꺼내 쓸 때 값을 치릅니다

부모 타입에 담긴 자식 타입은 각각의 타입으로 변환이 되어야 자식이 가지는 기능을 활용할 수 있습니다. 그래서 보통 instanceof 예약어로 자식 객체의 타입을 확인한 뒤 캐스팅해서 쓰게 됩니다.

 

문제는 이 타입 확인이 번거롭다는 점입니다. 담을 때는 편했는데 꺼낼 때마다 확인과 형변환을 반복해야 합니다. 그래서 Java는 컴파일 단계에서 컴파일러가 타입 체크를 엄격하게 할 수 있도록 Generic 기능을 제공합니다.

제네릭이 없으면 Object로 담고 매번 캐스팅합니다

제네릭 타입을 사용하지 않는 Box는 내용물을 Object 타입으로 담습니다.

public class Box {
  private Object object;
  public void set(Object object) { this.object = object; }
  public Object get() { return object; }
}
Box box = new Box();
box.set("hello");                 // String 타입을 Object 타입으로 자동 타입 변환해서 저장
String str = (String) box.get();  // Object 타입을 String 타입으로 강제 타입 변환해서 얻음

 

넣을 때는 자동 타입 변환이라 조용히 넘어가지만, 꺼낼 때는 (String) 강제 타입 변환이 필요합니다. 그리고 이 캐스팅이 맞는지는 컴파일러가 보장해 주지 않습니다.

제네릭은 타입을 미리 못 박아 캐스팅을 지웁니다

타입 파라미터 T를 두면 이야기가 달라집니다.

public class Box<T> {
  private T t;
  public T get() { return t; }
  public void set(T t) { this.t = t; }
}

이 한 벌의 코드가 사용하는 쪽에서 지정한 타입에 맞춰 전개됩니다.

 

Box<String> box = new Box<String>();이라고 쓰면 컴파일러는 T 자리가 전부 String으로 바뀐 클래스처럼 취급합니다.

Box<String> box = new Box<String>();
box.set("hello");
String str = box.get();
Box<Integer> box = new Box<Integer>();
box.set(6);
int value = box.get();

제네릭 타입을 사용하면 컴파일 단계에서 자동으로 지정 타입으로 변환되므로 캐스팅이 필요 없습니다. 꺼내는 자리의 괄호가 사라진 것이 눈에 보이는 변화이고, 타입이 어긋나면 실행 전에 걸린다는 것이 보이지 않는 변화입니다.

반응형