지네릭 클래스 : 클래스의 타입을 하나로 고정, 클래스명 뒤에 지네릭 표현

                     지네릭이 선언된 클래스를 객체 생성시 타입을 대입하지 않으면 Object 타입으로 적용

Class Box<T> {
    ArrayList<T> list = new ArrayList<T>();
    
    private T t;   
    T get(int i){ 
    	return ~~~~~
    }
    void add(T item)
    
}

지네릭 메서드 : 매개변수의 타입을 하나로 고정, 반환타입 앞에 지네릭 표현

public static <T> Box<T> setBox(T t) {	// 1번째T = 3번째T : 지네릭메서드 , 2번째T : 지네릭클래스 
    return ~~~;	// Box<T>타입
}

// 메서드 호출시
System.out.println(Box.<String>setBox("String"));
System.out.println(Box.setBox("String"));	// 생략가능
class Generics {

	public static void main(String[] args) {
	    int result1 = Util.sum("10", "20");		// int타입
	    System.out.println(result1);	// 30
		
	    Pool<Double> p1 = new Pool<Double>(20.0);
	    Double value = p1.get();
	    System.out.println(value);		// 20.0
	}
	
}

class Pool<T extends Double> {	// 지네릭 클래스
	T t;
	
	Pool00(T t) {
	    this.t = t;
	}
	void set(T t) {
	    this.t = t;
	}
	T get( ) {
	   return t;
	}
}

class Util {
	public static <T extends String> int sum(T t1, T t2) {	//지네릭 메서드
	    String v1 = t1;		// String 타입
	    String v2 = t2;		// String 타입
	    return Integer.parseInt(v1) + Integer.parseInt(v2);	// int(Integer)타입	
}

● 지네릭스 타입변수 T

 - 인스턴스 변수임.

 - static 멤버 X, 배열 생성 X (단, 배열을 위한 참조변수는 O), instanceof X

class Box<T> {
    T[] arr;		// 배열을 위한 참조변수 -> 가능
    
    T[] serArr() {
    	T[] arr = new T[arr.length]		// 배열생성 -> 불가
    }
}

● 상속

 - 대입된 타입 상속 X

Box<Apple> appleBox = new Box<Fruit>();

 - 지네릭 클래스 타입 상속 O

Box<Apple> appleBox = new FruitBox<Apple>();

 - 자식클래스에서 추가적인 타입 변수를 갖을 수 있음(∵ 부모 ≤ 자식)

public class ChildProduct<T, M, C> extends Product<T, M> {}

● 제한된 지네릭 클래스

 - 지네릭 타입에 extends를 사용하여 특정 타입의 자손만 대입 가능.(클래스, 인터페이스 가능)

    ex) : Fruit클래스의 자손만 클래스에 담을 수 있음.

    ex2) <T extends Fruit & Eatable> : Fruit클래스의 자손 & Eatable 인터페이스 구현 한 클래스만 가능

● 와일드카드

 - <? extends T> : T와 그 자손들만 가능

 - <? super T> : T와 그 조상들만 가능, class 구현시 사용 불가

 - <?> (=<? extends Object>) : 제한 없음