제한된 제네릭
-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>(); //ERROR!
인터페이스인 경우에도 extends 사용
interface Eatable{...}
class FruitBox<T extends Eatable> {...}
// FruitBox는 Eatable 인터페이스를 구현한 타입으로만 생성 가능하다
EX)
아래와 같은 클래스들이 존재한다.
public interface Eatable {}
public class Fruit implements Eatable{
@Override
public String toString() {return "Fruit";}
}
public class Apple extends Fruit{
@Override
public String toString() {return "Apple";}
}
public class Cherry extends Fruit{
@Override
public String toString() {return "Cherry";}
}
public class Toy {
public String toString() {return "Toy";}
}
그리고 이들을 담을 수 있는 Box클래스와 FruitBox클래스가 있다.
import java.util.ArrayList;
public class Box<T>{
ArrayList<T> list = new ArrayList<T>();
public void add(T item){list.add(item);}
T get(int i){return list.get(i);}
int size(){return list.size();}
@Override
public String toString() {
return list.toString();
}
}
public class FruitBox <T extends Fruit & Eatable> extends Box<T>{}
Box<T> 는 모든 타입들로 생성할 수 있지만, FruitBox<T extends Fruit & Eatable> extends Box<T> 는 Fruit을 extends하고, Eatable을 implements한 타입들로만 생성가능하다.
Apple과 Cherry는 이미 Fruit을 extends하고 있고, Fruit은 Eatable을 Implements하므로, Apple과 Cherry는 FruitBox를 생성할 수 있다.
예시 코드를 보자.
import lambda.nam.generics.fruitExample.*;
public class EX05 {
public static void main(String[] args) {
FruitBox<Fruit> fruitBox = new FruitBox<>(); //모든 Fruit을 담을 수 있다.
FruitBox<Apple> appleBox = new FruitBox<>(); //Apple은 Fruit을 상속받으므로 OK
FruitBox<Cherry> cherryBox = new FruitBox<>(); /Cherry는 Fruit을 상속받으므로 OK
/*ERROR*/ FruitBox<Cherry> cherryAppleBox = new FruitBox<Apple>(); //ERROR 타입 불일치
Box<Toy> toyBox = new Box<Toy>(); //Box는 모든 타입 가능
/*ERROR*/ FruitBox<Toy> toyBox = new FruitBox<Toy>();//FruitBox는 Fruit을 extends, Eatable을 implements해야함
fruitBox.add(new Fruit());
fruitBox.add(new Apple());
fruitBox.add(new Cherry());
appleBox.add(new Apple());
cherryBox.add(new Cherry());
}
}
제네릭스의 3가지 제약
-1. 타입 변수에 대입은 인스턴스 별로 다르게 가능
Box<Apple> appleBox = new Box<Apple>(); // OK. Apple객체만 가능
Box<Cherry> cherryeBox = new Box<Cherry>(); // OK. Cherry객체만 가능
-2. static 멤버에 타입 변수 사용 불가 (static은 모든 인스턴스에 공통)
class Box<T>{
static T item; // ERROR
static int compare(T t1, T t2({...} // ERROR
...
}
-3. 배열 생성할 때 타입 변수 사용불가. 타입 변수로 배열 선언은 가능. (new 다음에 T가 올 수 없다.)
class Box<T>{
T[] itemArr; // OK. T타입의 배열을 위한 참조변수
T[] toArray(){
T[] tmpArr = new T[itemArr.length]; // ERROR! 제네릭 배열 생성 불가
...
}
}
출처: 남궁성님 유튜브 강의
https://www.youtube.com/user/MasterNKS
'java' 카테고리의 다른 글
Generics 05 제네릭 형 변환 (0) | 2022.01.04 |
---|---|
Generics 05 와일드 카드, 제네릭 메서드 (0) | 2022.01.04 |
Generics 03 Iterator, HashMap과 제네릭스 (0) | 2022.01.03 |
Generics 02 제네릭스 용어, 제네릭 타입과 다형성 (0) | 2022.01.02 |
Generics 01 제네릭스란? (0) | 2021.12.31 |