포괄적인, 총괄적인, 일반적인
자바에서 제니릭(generic)이란 데이터의 타입(data type)을 일반화한다(generalize)는 것을 의미
==> 즉, 자바에서 제네릭은 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 말함 객체별로 다른 타입의 자료가 저장될 수 있도록 함
모든 종류의 타입을 다룰 수 있도록, 클래스나 메서드를 타입 매개변수(generic type)을 이용하여 선언하는 기법임
특정한 클래스에 원하는 객체 타입을 지정하여 지정된 객체만 저장하게 하는 자바 문법
동일한 프로그램 코드에 다양한 데이터 타입을 적용할 수 있도록 클래스와 메서드들을 일반화시켜 제네릭 메서드와 제네릭 클래스를 만들고, 제네릭 메서드나 제네릭 클래스에 개발자가 원하는 데이터 타입으로 구체화시켜 메서드나 클래스의 프로그램 코드를 틀에서 찍어내는 듯이 생산하는 기법임
다양한 타입의 객체들을 다루는 메서드나 다음에 학습할 컬렉션에서 컴파일 할 때 타입을 확인해 주는 기능
==> 즉, 다루어질 객체의 타입을 미리 명시해 줌으로써 번거로운 형변환 작업을 줄여준다는 장점이 있음. 또한 객체의 타입을 컴파일 시에 체크하여 주기 때문에 객체의 타입 안전성을 높여 준다는 장점도 있음.
jdk 1.5 버전부터 추가된 기능
데이터의 명확성과 안전성을 보장해줌
==> 다른 데이터 타입의 데이터가 들어올 경우, 컴파일 시점에서 error 발생
<E> : Element 를 의미하며 컬렉션에서 요소임을 나타냄
<T> : Type을 의미함
<V> : Value를 의미함
<K> : Key를 의미함
<예시1> : 제네릭 사용 X
Apple 클래스, Pencil 클래스 생성


=============================코드=============================
//////////// Apple 클래스
public class Apple {
void output() {
System.out.println("사과입니다!");
}
}
//////////// Pencil 클래스
public class Pencil {
void output() {
System.out.println("연필입니다!");
}
}
Apple 타입의 apple 변수와 Pencil타입의 pencil 변수를 만들 Goods_01, Goods_02클래스 생성


=============================코드=============================
//////////////// Apple변환타입의 apple 변수 생성
public class Goods1 {
private Apple apple;
public Apple getApple() {
return apple;
}
public void setApple(Apple apple) {
this.apple = apple;
}
}
//////////////// Pencil변환타입의 pencil 변수 생성
public class Goods2 {
private Pencil pencil;
public Pencil getPencil() {
return pencil;
}
public void setPencil(Pencil pencil) {
this.pencil = pencil;
}
}
Goods1, Goods2 객체를 활용하여 메서드 출력할 Goods_01 클래스 생성

=============================코드=============================
public static void main(String[] args) {
// Goods1 객체를 이용하여 Apple 객체를 추가하거나 가져오기
Goods1 goods1 = new Goods1();
// Apple 객체 타입만 입력이 가능
//Apple apple = new Apple();
//goods1.setApple(apple);
// 위 두 코드를 합하면 밑에처럼 작성 가능 ↓
goods1.setApple(new Apple()); // Apple 객체 생성
Apple apple = goods1.getApple();
apple.output();
goods1.getApple();
System.out.println();
// Goods2 객체를 이용하여 Pencil 객체를 추가하거나 가져오기
Goods2 goods2 = new Goods2();
// Pencil 객체 타입만 입력이 가능
goods2.setPencil(new Pencil()); // Pencil 객체 생성
Pencil pencil = goods2.getPencil(); // pencil 타입으로 호출
pencil.output();
}

위의 방법들을 한번에 처리하는 방법 : Object 활용 방법이 있다!
Goods 클래스 생성
=============================코드=============================
public class Goods {
private Object object;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
메인메서드로 출력할 Goods_02 클래스 생성

=============================코드=============================
public static void main(String[] args) {
Goods goods = new Goods();
goods.setObject(new Apple());
Apple apple = (Apple)goods.getObject(); // apple이 Apple의 타입이기 때문에 형변환이 필요!
// getObject는 Object타입임
apple.output();
System.out.println();
////////////////////////////////////////
Goods goods1 = new Goods();
goods1.setObject(new Pencil());
Pencil pencil = (Pencil)goods1.getObject(); //
pencil.output();
System.out.println();

위의 예시를 통해 알 수 있는 것
데이터를 저장할 때는 상관이 없지만, 저장된 데이터를 각각의 타입(Apple, Pencil)을 꺼내오기 위해서는 저장된 형태로 캐스팅(형변환)을 해야 함.
필드 자체가 Object 타입이기 때문에 get() 메서드를 가져오는 타입 또한 항상 Object 타입이 됨
따라서 Apple 객체를 저장했을 때는 get() 메서드로 가져온 Object 타입을 Apple 타입으로, Pencil 객체를 저장했을 때는 가져온 Object 타입을 Pencil 객체 타입으로 캐스팅을 해주어야 함
정확하게 해당 객체 타입으로 형변환을 해주는 경우에는 문제가 발생하지 않지만, 다른 객체 타입으로 형변환을 해주게 되면 실행 중에 예외(ClassCaseException)가 발생할 수 있음
이렇게 되면 정상적으로 프로그램이 종료되지 않는 문제가 발생할 수 있음
Object 타입으로 선언된 변수에 데이터가 들어가는 경우, 해당 변수에 있는 값을 꺼내고 싶은 경우에는 반드시 형변환 작업이 필요함
이러한 형변환 작업이 자주 일어나게 되면 프로그램 성능이 저하될 수 있음
이 문제점을 해결하는 것이 바로 제네릭(generic)임
그렇다면 이제 제네릭을 활용하여 형변환 없이 출력해보자!
Good 클래스 생성
public class Good<T> { // T는 타입이라는 뜻
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
메인메서드로 출력할 Good_03 클래스 생성

=============================코드=============================
public static void main(String[] args) {
Good<Apple> good1 = new Good<Apple>(); // Apple 객체 타입만 받겠다!
good1.setT(new Apple());
Apple apple = good1.getT();
apple.output();
System.out.println();
///////////////////////////////////////
Good<Pencil> good2 = new Good<>(); // new Good<Pencil>의 Pencil은 생략 가능
good2.setT(new Pencil());
Pencil pencil = good2.getT();
pencil.output();
}
