제한된 지네릭 클래스
extends로 대입할 수 있는 타입을 제한
class FruitBox<T extends Fruit> { // Fruit의 자손만 타입으로 지정가능
ArrayList<T> list = new ArrayList<T>();
...
}
FruitBox<Apple> appleBox = new FruitBox<Apple>(); // OK
FruitBox<Toy> toyBox = new FruitBox<Toy>(); // 에러! Toy는 Fruit의 자손이 아님
인터페이스인 경우도 extends를 사용
interface Eatable {}
class FruitBox<T extends Eatable> {...}
예제
public class Ex1 {
public static void main(String[] args) {
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>(); // Fruit의 자식이고 Eatble을 구현한 객체타입만 들어올 수 있음.
FruitBox<Apple> appleBox = new FruitBox<>();
FruitBox<Grape> grapeBox = new FruitBox<>();
//FruitBox<Toy> toyBox = new FruitBox<Toy>(); // 에러 타입 불일치
//FruitBox<Grape> grapeBox1 = new FruitBox<Apple>(); // 에러
Box<Toy> box = new Box<Toy>(); // Box는 제한이 없고, FruitBox에는 제한이 있음, 대신 Toy만 넣을 수 있음
Box<Fruit> fruitBox1 = new FruitBox<>();
fruitBox.add(new Fruit());
fruitBox.add(new Apple());
fruitBox.add(new Grape());
appleBox.add(new Apple());
//appleBox.add(new Grape()); // 에러! Grape는 Apple의 자식이 아님
//appleBox.add(new Fruit()); // 에러! Fruit는 Apple의 자식이 아님
grapeBox.add(new Grape());
fruitBox1.add(new Apple());
fruitBox1.add(new Grape());
System.out.println("fruitBox = " + fruitBox);
System.out.println("appleBox = " + appleBox);
System.out.println("grapeBox = " + grapeBox);
}
}
class Fruit implements Eatable{
public String toString() {
return "Fruit";
}
}
class Apple extends Fruit{
public String toString() {
return "APPLE";
}
}
class Grape extends Fruit{
public String toString() {
return "GRAPE";
}
}
class Toy {
public String toString() {
return "TOY";
}
}
interface Eatable{ }
class FruitBox<T extends Fruit & Eatable> extends Box<T> { // Fruit 자손이면서 Eatable을 구현한 객체만
}
class Box<T> {
ArrayList<T> list = new ArrayList<T>(); // item을 저장할 박스
void add(T item){ // 박스에 아이템을 추가
list.add(item);
}
T get(int i) { // 박스에서 item을 꺼낼 때
return list.get(i);
}
int size() { // 박스에 들어간 item 수
return list.size();
}
public String toString() {
return list.toString();
}
}
fruitBox = [Fruit, APPLE, GRAPE]
appleBox = [APPLE]
grapeBox = [GRAPE]
그런데 상식적으로는 말이 안되지만 Eatable이 Apple에만 구현이 되어있다면 어떨까 문득 생각했다..
class Fruit {
public String toString() {
return "Fruit";
}
}
class Apple extends Fruit implements Eatable{ // 과일을 먹지못하는데 사과를 먹는다는 모순
public String toString() {
return "APPLE";
}
}
class Grape extends Fruit{
public String toString() {
return "GRAPE";
}
}
역시 Eatable이 구현된 Apple만 FruitBox에 넣을 수 있었다!!
이유가 뭘까? 바로 이것 때문!!!!
class FruitBox<T extends Fruit & Eatable> extends Box<T> { // Fruit 자손이면서 Eatable을 구현한 객체만
지네릭스의 제약
타입 변수에 대입은 인스턴스 별로 다르게 가능
Box<Apple> appleBox = new Box<Apple>(); // Ok. Apple 객체만 저장가능
Box<Grape> grapeBox = new Box<Grape>(); // Ok. Grape 객체만 저장가능
1. static 멤버에 타입 변수 사용 불가
class Box<T> {
static T time; // 에러
static int compare(T t1, T t2) {...} // 에러
}
인스턴스 마다 다르게 가능한 타입변수를 공통으로 사용하는 멤버에 넣을 수 없다.
2. 배열,객체 생성할 때 타입 변수 사용불가, 타입 변수로 배열 선언은 가능
class Box<T> {
T[] itemArr; // Ok. T타입의 배열을 위한 참조변수
...
T[] toArray() {
T[] tmpArr = new T[item.length]; // 에러. 지네릭 배열 생성불가(new 다음에 T는 못나옴)
}
}
'Java' 카테고리의 다른 글
[Java] 지네릭 타입의 형변환 (0) | 2024.05.10 |
---|---|
[Java] 와일드 카드, 지네릭 메서드 (0) | 2024.05.10 |
[Java] Iterator<E>, Map<K, V> (0) | 2024.05.09 |
[Java] 지네릭스란? (0) | 2024.05.09 |
[Java] Collections 컬렉션을 위한 메서드 (0) | 2024.05.08 |