일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 카카오 면접
- Spring
- 클린아키텍처
- 알고리즘정렬
- 알고리즘
- ElasticSearch
- 티스토리챌린지
- 카카오
- 자바
- 예제로 배우는 스프링 입문
- effectivejava
- 스프링핵심원리
- k8s
- 자바스크립트
- 이펙티브 자바
- java
- Sort
- 엘라스틱서치
- JavaScript
- 이차전지관련주
- 오블완
- 김영한
- 스프링
- 스프링 핵심원리
- 코딩테스트
- Effective Java
- 스프링부트
- 이펙티브자바
- kubernetes
- Effective Java 3
- Today
- Total
Kim-Baek 개발자 이야기
제네릭 타입 소거 (컴파일/런타임) 본문
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
// stringBox.setValue(10); // 컴파일 오류: 타입 불일치
1. 제네릭 타입 소거 (Generic Type Erasure)
자바에서 제네릭(Generic)은 코드의 재사용성과 타입 안전성을 증가시키는 중요한 기능이지만, 자바 컴파일러는 **타입 소거(Erasure)**를 사용하여 제네릭을 처리합니다. 타입 소거란 컴파일 시점에서 제네릭 타입 정보를 제거하는 과정을 말합니다. 이 때문에 자바의 제네릭은 런타임에 타입 정보를 알 수 없으며, 컴파일 타임에만 제네릭이 유효하게 됩니다.
제네릭 타입 소거의 동작 원리
자바 컴파일러는 제네릭을 처리할 때, 제네릭 타입의 인스턴스를 실제 클래스 타입으로 변경합니다. 즉, 제네릭 타입은 **런타임에 원시 타입(raw type)**으로 변환됩니다.
예를 들어, 다음과 같은 코드가 있을 때:
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
컴파일러는 Box<T>를 처리할 때 제네릭 타입 매개변수 T를 실제 타입으로 대체합니다. 예를 들어 Box<String>은 Box로 컴파일되며, 이때 제네릭 정보는 소거되고, 실제 타입은 런타임에 결정됩니다. T는 실제로 Object로 대체될 수도 있으며, 구체적인 타입이 지정되어 있으면 그 타입으로 바뀝니다.
결과적으로:
- 컴파일 타임: 제네릭의 타입 정보를 이용해 타입 안전성을 확보합니다.
- 런타임: 제네릭 타입 정보는 소거되고 원시 타입이 사용됩니다.
타입 소거의 예시
Box<String> box = new Box<>();
box.setValue("Hello");
// 컴파일 타임에는 Box<String> 타입으로 동작하지만,
// 실제로 런타임에서는 타입 정보가 소거되고 Box가 사용됩니다.
2. 컴파일 타임과 런타임
자바에서 제네릭을 사용할 때 컴파일 타임과 런타임에 중요한 차이가 있습니다. 제네릭 타입 소거는 컴파일 타임에 이루어지고, 런타임에 제네릭 정보가 손실됩니다.
컴파일 타임
- 타입 안전성 확보: 제네릭을 사용하면 컴파일 타임에 타입 오류를 미리 체크할 수 있습니다.
- 예시:제네릭을 사용하면 Box<String>에 String만 허용되므로, Box에 다른 타입을 넣으려고 하면 컴파일 타임에 오류가 발생합니다.
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
// stringBox.setValue(10); // 컴파일 오류: 타입 불일치
런타임
- 타입 정보 손실: 제네릭 타입은 런타임에 소거되므로, 런타임에서는 원시 타입(raw type)만 알 수 있습니다. 즉, 제네릭 타입을 객체에 대한 정보가 없으며, 반사(reflection)나 기타 방법을 통해서는 제네릭 타입을 알 수 없습니다.
- 예시:Box<String>의 경우 런타임에 Box로만 처리되고, String에 대한 정보는 사라집니다.
Box<String> stringBox = new Box<>();
System.out.println(stringBox.getClass()); // 출력: class Box
3. 제네릭과 타입 소거의 예시
public class Main {
public static void main(String[] args) {
Box<Integer> intBox = new Box<>();
intBox.setValue(10);
Box<String> strBox = new Box<>();
strBox.setValue("Hello");
// 컴파일 타임에는 Box<Integer>, Box<String> 각각에 대한 타입 안전성 보장
// 하지만 런타임에는 Box만 존재하며, Integer나 String 타입 정보는 사라짐
}
}
위 코드에서 Box<Integer>와 Box<String>은 컴파일 타임에 타입 안전성을 보장하지만, 런타임에 실제로 어떤 타입이 사용되는지 알 수 없습니다. 이로 인해 타입 정보를 런타임에서 추적할 수 없는 제약이 있습니다.
4. 타입 파라미터의 경계 (Bounded Type Parameters)
제네릭은 타입 파라미터에 대한 경계를 설정할 수 있습니다. 예를 들어, T가 특정 클래스나 인터페이스를 상속한 타입만 허용하도록 할 수 있습니다.
public class Box<T extends Number> { // T는 Number의 하위 타입만 허용
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
이 경우, T는 Number를 확장한 타입만 가능하므로, Box<Integer>나 Box<Double>은 허용되지만 Box<String>은 허용되지 않습니다. 이러한 경계는 컴파일 타임에 체크됩니다.
결론
- 제네릭 타입 소거는 자바 컴파일러가 제네릭의 타입 정보를 컴파일 타임에 소거하고, 런타임에는 원시 타입을 사용하도록 하는 메커니즘입니다.
- 컴파일 타임에 제네릭은 타입 안전성을 제공하지만, 런타임에서는 제네릭 타입 정보가 소거되어 원시 타입만 남습니다.
- 제네릭은 컴파일 타임에만 타입 검사를 제공하며, 런타임에서는 제네릭 정보가 소거되므로 타입 정보에 접근할 수 없습니다.
'개발 > java basic' 카테고리의 다른 글
자바 리플렉션이란 (0) | 2024.11.24 |
---|---|
리액티브 프로그래밍이란 (0) | 2024.11.17 |
일급 컬렉션이란? (0) | 2024.11.13 |
제네릭이란 무엇일까 (0) | 2024.11.12 |
자바에서 코틀린 - 6장 자바에서 코틀린 컬렉션으로 (0) | 2023.04.17 |