Notice
Recent Posts
Recent Comments
Link
변수의 기록
java(자바)- 제네릭(Generic)의 구조적 이해 – 타입, 힙/스택, 참조형까지 완전 정리 본문
자바 제네릭(Generic)의 구조적 이해 – 타입, 힙/스택, 참조형까지 완전 정리
1. 제네릭이란?
제네릭(Generic) 은 자바에서 컴파일 시점에 타입을 명시적으로 지정할 수 있게 하는 문법이다.
타입 안정성을 높이고 형변환을 줄이기 위해 도입되었으며, 대표적으로 List<T>, Map<K,V>, Box<T> 등의 형태로 사용된다.
예시:
List<String> list = new ArrayList<>();
list.add("abc");
String value = list.get(0); // 형변환 없이 사용 가능
2. 자바 제네릭의 핵심 특징 – 타입 소거(Type Erasure)
자바의 제네릭은 타입 소거(Type Erasure) 방식으로 동작한다.
즉, 제네릭 타입 정보는 컴파일 시에만 존재하고, 런타임에는 모두 제거된다.
예:
List<String> list = new ArrayList<>();
→ 컴파일 후:
List list = new ArrayList(); // 타입 정보(String)는 사라짐
Object val = list.get(0); // 런타임에는 Object로 처리
왜 타입 소거를 사용하는가?
기존(자바 1.4 이전) 코드와의 호환성과 JVM 구조를 단순화하기 위한 선택이다.
런타임에 각 타입별 클래스를 생성하는 C++ 템플릿 방식과 다르다.
3. 왜 기본형은 제네릭에 넣을 수 없는가?
자바 제네릭은 내부적으로 Object 기반으로 데이터를 처리한다.
하지만 int, double, boolean 등의 **기본형(primitive type)**은 Object가 아니다.
List<int> list = new ArrayList<>(); // 컴파일 에러
기본형을 제네릭에 사용할 수 없는 이유는:
- 타입 소거 후 모든 T는 Object로 변환됨
- Object obj = 10; → 실제로는 Object obj = new Integer(10); (오토박싱 발생)
- 따라서 Object에는 기본형을 직접 담을 수 없으며, 기본형은 제네릭에 사용 불가
해결책: Wrapper 클래스 사용
기본형 | 래퍼 클래스 |
int | Integer |
double | Double |
boolean | Boolean |
List<Integer> list = new ArrayList<>();
list.add(10); // 오토박싱: int → Integer
int val = list.get(0); // 언박싱: Integer → int
4. 제네릭과 참조형의 관계
자바에서 제네릭 타입은 반드시 참조형이어야 한다.
이유:
- 타입 소거로 인해 내부적으로 Object로 변환됨
- Object는 참조형의 최상위 타입이므로, 참조형만이 대상이 될 수 있음
- 기본형은 Object의 하위가 아니므로 허용되지 않음
예외처럼 보이는 배열 타입:
List<int[]> list = new ArrayList<>();
int[] arr = {1, 2, 3};
list.add(arr);
- int[]는 참조형이므로 사용 가능
- 배열은 자바에서 객체(Object) 로 간주되며, 힙에 저장됨
5. 힙/스택 메모리 관점에서 본 제네릭
자바는 메모리를 크게 힙(heap) 과 스택(stack) 으로 나눈다.
구분 | 저장 위치 | 설명 |
int x = 10; | 스택 | 지역 변수, 기본형 |
Integer x = 10; | 힙 | 오토박싱된 객체 |
int[] arr = new int[3]; | 힙 | 배열도 객체이므로 힙 |
List<Integer> | 힙 | 내부 요소는 모두 객체, 힙에 저장 |
컬렉션은 내부적으로 다음과 같은 구조로 데이터를 저장한다:
Object[] elementData; // ArrayList 내부 구조
→ 따라서 제네릭을 통해 저장되는 값은 결국 모두 Object로 저장, 즉 힙에 위치한 참조값만 저장된다.
이 구조 때문에 list.get(0)의 결과도 항상 Object로 처리된다:
List list = new ArrayList();
list.add(13); // int → Integer → 힙
int x = (int) list.get(0); // ❌ 런타임 에러
int x = (Integer) list.get(0); // ✅ 다운캐스팅 + 언박싱
6. 배열과 제네릭 – 예외적 관계
비록 int는 제네릭에 사용할 수 없지만, int[]는 객체이므로 가능하다.
List<int[]> list = new ArrayList<>();
list.add(new int[]{1, 2, 3});
System.out.println(list.get(0)[1]); // 출력: 2
- 배열은 힙 메모리에 존재
- 배열 타입은 참조형 → 제네릭에 사용 가능
7. 정리: 자바 제네릭과 타입/메모리의 상관관계
항목 | 설명 |
제네릭은 참조형만 허용 | 기본형은 타입 소거 후 Object로 변환 불가 |
기본형을 쓰고 싶다면 | Wrapper 클래스 (Integer, Double) 사용 |
제네릭은 타입 소거됨 | 컴파일 후 List<T> → List, T → Object |
get()은 항상 Object 리턴 | → 형변환 또는 언박싱 필요 |
배열은 참조형 | int[], String[]는 모두 제네릭에 사용 가능 |
컬렉션 내부 저장소 | Object[] 형태 → 힙 메모리 기반 |
'자바 > 자바' 카테고리의 다른 글
Java 신 개념 총정리 — char, this, switch, 생성자, 자료형 설계 이유까지 (day2) (1) | 2025.06.19 |
---|---|
Java의 신 Day 1 정리 (0) | 2025.06.18 |
(JAVA) 불변 객체 (0) | 2025.04.25 |
(java) 값이 중복되는 객체를 제거 hash set , HashMap 사용 (1) | 2025.04.24 |
(Java) Set의 구조와 활용 - ADT 관점으로 이해 (0) | 2025.04.23 |