자바의 정석 챕터 13을 읽고 정리
1. 지네릭스란?
- 지네릭스는 다양한 타입의 객체들을 다루는 메소드나 컬렉션 클래스에 컴파일 시 타입 체크를 해주는 기능
- 타입 안정성 제공
- 타입체크와 형변환을 생략할 수 있어서 코드가 간결해짐
2. 지네릭 클래스 선언
- 클래스에 지네릭 타입을 넣을 수 있다.
class Box {
Object item;
void setItem(Object item) {
this.item = item;
}
Object getItem() {
return item;
}
}
// 지네릭 타입 T를 선언
class Box<T> {
T item;
void setItem(T item) {
this.item = item;
}
T getItem() {
return item;
}
}
- T는 타입변수
지네릭스의 용어
Box<T>: 지네릭 클래스. 'T의 Box' 또는 'T Box'라고 읽는다.
T: 타입 변수 또는 타입 매개변수
Box: 원시 타입(raw type)
지네릭스의 제한
- 지네릭 클래스 Box의 객체를 생성할 때, 객체별로 다른 타입을 지정할 수 있다.
Box<Apple> = new Box<>();
Bpx<Grape> = new Box<>();
- static멤버에는 타입변수 T를 사용할 수 없다.
- static은 모든 객체에 동일하게 동작해야 하기 때문
T[] itemArr; // T타입의 배열을 위한 참조변수
T[] tmpArr = new T[itemArr.length]; // 에러
- 지네릭 타입의 배열은 사용할 수 없다.
- new 연산자 때문
- new는 컴파일 시점에 타입T가 뭔지 정확히 알아야 한다.
- instanceof 연산자도 마찬가지.
- 지네릭 배열이 필요한 경우 Object 배열을 생성하여 복사한 뒤 T[]로 형변환 해서 사용.
3. 지네릭 클래스의 객체 생성과 사용
- 지네릭 클래스 Box<T>가 있다고 가정하면, 이 Box<T>는 T타입의 객체만 저장 가능하다.
class Box<T> {
ArrayList<T> list = new ArrayList<>();
void add(T item) { list.add(item); }
T get(int i) { return list.get(i); }
ArrayList<T> getList() { return list; }
int size() { return list.size(); }
public String toString() { list.toString(); }
}
- Box<T>의 객체를 생성할 때는 참초변수와 생성자에 대입된 타입이 일치해야 한다.
Box<Apple> appleBox = new Box<Apple>();
Box<Apple> appleBox = new Box<>();
Box<Apple> appleBox = new Box<Grape>(); // 에러
- 두 타입이 상속관계여도 마찬가지. Apple이 Fruit의 자식이라고 가정
Box<Fruit> appleBox = new Box<Apple>(); // 에러
- 두 개의 지네릭 타입이 상속관계, 대입된 타입이 같은 경우 가능. FruitBox가 Box의 자식이라고 가정
Box<Apple> appleBox = new FruitBox<Apple>();
Box<Apple> appleBox = new FruitBox<>(); // 생략 가능
- 생성된 Box<T> 객체에 void add(T item)으로 객체를 추가할 때, 대입된 타입과 다른 타입의 객체는 추가할 수 없다.
Box<Apple> appleBox = new Box<>();
appleBox.add(new Apple());
appleBox.add(new Grape()); // 에러
- 타입 T가 Fruit인 경우 void add(Fruit item)이 되므로 Fruit 자식들은 추가가 가능하다.
Box<Fruit> fruitBox = new Box<>();
fruitBox.add(new Fruit());
fruitBox.add(new Apple());
4. 제한된 지네릭 클래스
- extends로 특정 타입의 자식들만 대입할 수 있게 제한할 수 있다.
class FruitBox<T extends Fruit> { // Fruit의 자식들만 타입으로 지정 가능
ArrayList<T> list = new ArrayList<>();
}
FruitBox<Apple> appleBox = new FruitBox<>();
FruitBox<Toy> toyBox = new FruitBox<>(); // 에러
- 인터페이스를 구현해야 하는 제약을 줄 때도 extends 사용
interface Eatable {}
class FruitBox<T extends Eatable> {
...
}
- Fruit의 자식이면서 Eatable 인터페이스를 사용해야 할 경우
class FruitBox<T extends Fruit & Eatable> {
...
}
5. 와일드 카드
class Juicer {
static Juice makeJuice(FruitBox<Fruit> box {
String tmp = "";
for (Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
}
- 위의 클래스는 지네릭 클래스가 아니다.
- static 이므로 T를 사용할 수 없다.
FruitBox<Fruit> fBox = new FruitBox<>();
FruitBox<Apple> aBox = new FruitBox<>();
...
System.out.println(Juicer.makeJuice(fBox); // FruitBox<Fruit>
System.out.println(Juicer.makeJuice(aBox); // 에러 FruitBox<Apple>
- 이렇게 지네릭 타입을 FruitBox<Fruit>으로 고정하면, <Apple>은 makeJuice()의 매개변수가 될 수 없다.
- 여러개를 만든다?
- 지네릭 타입이 다르다고 오버로딩은 되지 않는다.
- 이럴 때 와일드 카드(?)를 사용한다.
<? extends T>: 와일드 카드 상한 제한. T와 T의 자식들만 가능
<? super T>: 와일드 카드 하한 제한. T와 T의 부모들만 가능
<?>: 제한 없음. 모든 타입 가능.
static Juice makeJuice(FruitBox<? extends Fruit> box) {
String tmp = "";
for (Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
- 이 메소드는 <Apple>, <Grape>도 가능하다.
FruitBox<Fruit> fBox = new FruitBox<>();
FruitBox<Apple> aBox = new FruitBox<>();
...
System.out.println(Juicer.makeJuice(fBox); // FruitBox<Fruit>
System.out.println(Juicer.makeJuice(aBox); // FruitBox<Apple>
6. 지네릭 메소드
- 메소드의 선언부에 지네릭 타입이 선언된 메소드를 지네릭 메소드라고 한다.
static <T> void sort(List<T> list, Comparator<? super T> c)
- 앞서 나왔던 makeJuice()를 지네릭 메소드로 바꾸면?
static <T extends Fruit> Juice makeJuice(FruitBox<T> box) {
String tmp = "";
for(Fruit f : box.getList()) temp += f + " ";
return new Juice(temp);
}
- 이 메소드를 호출 할 때는 타입변수에 타입을 대입해야 한다.
FruitBox<Fruit> fBox = new FruitBox<>();
...
System.out.println(Juicer.<Fruit>makeJuice(fBox));
System.out.println(Juicer.makeJuice(fBox)); // 사실 생략해도 컴파일러가 타입을 추정가능함
'개발 > Java&Kotlin' 카테고리의 다른 글
[Spring] Validation 적용해보기 (0) | 2022.08.18 |
---|---|
[Spring] 스웨거(Swagger) 라이브러리 (1) | 2022.08.17 |
[Java] 컬렉션 프레임워크 (2) (0) | 2022.08.16 |
[Java] 컬렉션 프레임워크 (1) (1) | 2022.08.12 |
[Spring] 스프링 시큐리티 (3) (2) | 2022.08.12 |