제네릭(Generic) = 결정되지 않은 타입을 파라미터로 처리하고 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능

<> 기호가 보이면 제네릭이다

<> 안에는 ‘클래스’만 들어갈 수 있다

<T> = T가 타입 파라미터임을 뜻하는 기호로, 타입이 필요한 자리에 T를 사용할 수 있음을 알려주는 역할을 한다.

class Program<T> { // < > 모형자
    T t; // 제네릭 타입 T를 멤버 변수로 선언

    void in(T t) { // 제네릭 타입 T를 매개변수로 받는 메서드 in 선언
        this.t = t; 
    }
    T get() { // 제네릭 타입 T를 반환하는 메서드 get 선언
        return t; 
    }
}
class Java { 
    String s; 
    Java(String s) {
        this.s = s; 
    }
    void show() { 
        System.out.println(s); 
    }
}
class DB { 
    String s; 
    DB(String s) {
        this.s = s; 
    }
    void show() { 
        System.out.println(s); 
    }
}
public class Test {
    public static void main(String[] args) {

        // Program 클래스에 제네릭 타입으로 Java를 설정하여 Program 객체 생성
        Program<Java> p = new Program<Java>();

        p.in(new Java("java")); // Java 객체를 Program 객체에 저장
        Java j = p.get(); // Program 객체로부터 Java 객체를 가져옴
        j.show(); // Java 객체의 show 메서드 호출

        // Program 클래스에 제네릭 타입으로 DB를 설정하여 Program 객체 생성
        Program<DB> p2 = new Program<DB>();
        p2.in(new DB("db")); // DB 객체를 Program 객체에 저장
        DB j2 = p2.get(); // Program 객체로부터 DB 객체를 가져옴
        j2.show(); // DB 객체의 show 메서드 호출
class Gen<T> {

	T a, b;

	Gen(T a, T b) {
		this.a = a;
		this.b = b;
	}

	T one() {
		return a;
	}

	T two() {
		return a;
	}

	boolean three() {
		return a.equals(b);
	}
}

public class test {

	public static void main(String[] args) {

		Gen<String> g = new Gen<String>("seoul", "busan");

		System.out.println(g.one()); // seoul 출력

		System.out.println(g.two()); // busan 출력

		System.out.println(g.three()); // false 출력 (두 문자열 비교)

	}
}

제네릭 메소드

class AA{
	@Override
	public String toString() {
		return"AA";
	}
}
class BB{
	@Override
	public String toString() {
		return"BB";
	}
}
class In{
	<T> void show(T t) { // 제너릭 메소드
		System.out.println(t); //객체 출력 -> 클래스명@16진수
	}
}

public class test {

	public static void main(String[] args) {
		
		AA a=new AA();
		In i=new In();
		i.<AA>show(a);
		i.<BB>show(b);

	}
}

제네릭 객체배열 스택(LIFO)구조

class St<T> {
	int n;
	Object[] st;

	St() {
		st = new Object[3]; // 객체배열
		n = 0;
	}

	public void push(T t) {
		if (n == 3) { // 스택이 다 차있으면, 요소를 더 이상 삽입 할 수 없다.
			return; // 함수종료
		}
		st[n] = t;
		n++;
	}

	public T pop() {
		if (n == 0) { // 스택이 비어있어서 요소를 꺼낼수 없다.
			return null;
		}
		n--;
		return (T) st[n];
	}
}

public class test {

	public static void main(String[] args) {

		St<String> s = new St<String>();
		s.push("java");
		s.push("Spring");
		s.push("MySql");

		for (int i = 0; i < 3; i++) {
			System.out.println(s.pop());
		}

		St<Integer> s2 = new St<Integer>();
		s2.push(1); // Integer i=1; = new Integer(11)
		s2.push(2);
		s2.push(3);

		for (int i = 0; i < 3; i++) {
			System.out.println(s2.pop());

		}
	}
}

제네릭 클래스 제한