자바의 정석[기초편]으로 공부한 내용을 정리한 글입니다.
제한된 지네릭 클래스
요점:
<T extends Fruit>처럼 extends를 써서 타입 변수에 들어올 수 있는 타입을 제한할 수 있습니다.
예제
class FruitBox<T extends Fruit> {
ArrayList<T> list = new ArrayList<T>();
...
}
- FruitBox는 Fruit 또는 그 자손 클래스만 T로 받을 수 있습니다.
- 예를 들어 FruitBox<Apple>은 OK (Apple이 Fruit의 자손).
- FruitBox<Toy>는 에러 → Toy는 Fruit을 상속받지 않았기 때문.
interface Eatable { ... }
class FruitBox<T extends Eatable> { ... }
- 인터페이스일 경우에도 extends를 사용합니다. (자바에서는 클래스나 인터페이스 모두 extends로 제한)
- implements는 실제 구현할 때 쓰는 키워드이고, 타입 제한에서는 extends로 통일됩니다.
지네릭스의 제약
지네릭은 강력하지만 몇 가지 제약 사항이 존재합니다.
1. 타입 변수는 인스턴스마다 다르게 설정 가능
Box<Apple> appleBox = new Box<Apple>();
Box<Grape> grapeBox = new Box<Grape>();
- Box는 하나의 클래스지만, Apple과 Grape라는 다른 타입 변수로 여러 객체 생성 가능.
- 즉, Box<T>의 T는 인스턴스마다 다를 수 있음.
2. static 멤버에 타입 변수 사용 불가
class Box<T> {
static T item; // ❌ 에러
static int compare(T t1, T t2) { ... } // ❌ 에러
}
- static 변수나 static 메서드는 클래스 로딩 시점에 메모리에 올라가야 합니다.
- 그런데 타입 변수 T는 인스턴스를 생성할 때 결정되므로, static에는 사용할 수 없습니다.
3. 타입 변수로 배열 생성은 불가
T[] itemArr; // ✅ 선언은 가능
T[] tmpArr = new T[]; // ❌ new T[길이]는 에러
- 배열을 선언만 하는 건 가능 (T[] itemArr)
- 하지만 new T[]처럼 직접 배열 생성은 불가능 → 타입이 컴파일 시점에 결정되지 않기 때문
- 해결 방법: Object[]로 생성하거나, Array.newInstance() 사용 등
'Java' 카테고리의 다른 글
열거형(enum) (0) | 2025.06.26 |
---|---|
와일드 카드, 지네릭 메서드 (0) | 2025.06.26 |
Iterator, HashMap과 지네릭스 (0) | 2025.06.25 |
지네릭 다형성 (0) | 2025.06.25 |
타입 변수 (0) | 2025.06.25 |