JAVA2_03_제한된 지네릭 클래스

charl hi·2021년 9월 26일
0

JAVA2

목록 보기
3/8

링크텍스트

제한된 지네릭 클래스

  • extends로 대입할 수 있는 타입을 제한

예)

class FruitBox<T extends Fruit> {
	ArrayList<T> list = new ArrayList<T>();
...
}
  • ✨✨<T extends Fruit> : Fruit클래스 포함 자손만 대입 가능
FruitBox<Apple> appleBox = new FruitBox<Apple>();	//(O)
FruitBox<Toy> toyBox = new FruitBox<Toy>();	//(X) Toy는 Fruit의 자손이 아니기에

인터페이스 경우

  • 인터페이스 경우에도 extends 사용

예)

interface Eatable {}
class FruitBox<T extends Eatable> {...}
  • ✨implements 안씀!!!
  • ✨✨<T extends Eatable> : Eatable인터페이스를 구현한 클래스만 대입 가능


ex12_03

import java.util.ArrayList;

public class Ex12_03 {

	public static void main(String[] args) {
		FruitBox<Fruit> fBox = new FruitBox<>();
		FruitBox<Apple> aBox = new FruitBox<>();
		FruitBox<Grape> gBox = new FruitBox<>();
//		FruitBox<Grape> gBox = new FruitBox<Apple>();	//타입불일치
//		FruitBox<Fruit> gBox = new FruitBox<Apple>();	//타입불일치
//		FruitBox<Toy> tBox = new FruitBox<>();	//Toy는 FruitBox의 타입변수에 못들어감
		
		fBox.add(new Fruit());
		fBox.add(new Apple());	//다형성O
		fBox.add(new Grape());
		
		aBox.add(new Apple());
//		aBox.add(new Fruit());
//		aBox.add(new Grape());
		
		gBox.add(new Grape());
//		gBox.add(new Fruit());
//		gBox.add(new Apple());
		
		System.out.println(fBox.size());
		System.out.println(fBox);
		for(int i=0; i<fBox.size(); i++) {
			System.out.println(fBox.get(i));
		}
		
		System.out.println(aBox.size());
		System.out.println(aBox);
		for(int i=0; i<aBox.size(); i++) {
			System.out.println(aBox.get(i));
		}
		
		System.out.println(gBox.size());
		System.out.println(gBox);
		for(int i=0; i<gBox.size(); i++) {
			System.out.println(gBox.get(i));
		}

	}

}

interface Eatable {}

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";	}
}

class Box<T>{
	ArrayList<T> list = new ArrayList<>();
	void add(T item) {	list.add(item);}
	T get(int i) {	return list.get(i);}
	int size() {	return list.size();}
	public String toString() {	return list.toString();}
}

class FruitBox<T extends Fruit & Eatable> extends Box<T>{}

//타입변수: Fruit클래스를 상속받고(본인 또는 자손이고) Eatable인페를 구현한 클래스
//**따로 쓰지않고 &로 같이 함!!
//사실 여기서 Fruit가 Eatable을 구현하기에 (& Eatable)을 안써도 된다.
//Box<T>를 상속받음

3
[맛있는Fruit, 아침엔Apple, 달디단Grape]
맛있는Fruit
아침엔Apple
달디단Grape
1
[아침엔Apple]
아침엔Apple
1
[달디단Grape]
달디단Grape


지네릭스의 제약

1. ✨static멤버에 타입변수 사용 불가

  • 타입변수에 대입은 인스턴스 별로 다르게 가능
  • 왜?? static멤버는 모든 인스턴스에 공통이니까!!

더 자세히 말하면,
static은 인스턴스 생성과 별도로 선언순간 메모리에 올라가 있다. 그런데 그런 static으로 선언된 메소드에 인스턴스가 생성되는 시점에 결정되는 제네릭 타입을 매개변수로 받을 수는 없을 것이다. - by.지네릭vs.와일드카드

class Box<T>{
	static T item;	//(X)에러
	static int compare(T t1, T t2) {...}	//(X)에러
}

2. ✨객체, 배열 생성할 때 타입변수 사용 불가

-> 💖타입변수로 배열 선언은 가능

class Box<T>{
	T[] itemArr;	//(O) T타입의 배열을 위한 참조변수
	...
	T[] toArray() {
		T[] tmpArr = new T[itemArr.length];
		//(X)에러. 지네릭 배열 생성 불가!!!!!
  • new + 다음엔 확정된 타입이 와야 하니까!!
    -> ❌new T(), new T[]



Ref

0개의 댓글