제네릭 이란 데이터형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법을 말한다.
우리는 지금까지 int, String 이런식으로 타입을 지정해서 변수를 선언해주거나 메소드를 지정해주었었다.
같은 메소드여도 오버로딩해서 여러개를 생성해주어야한다고 이전 포스트들에서도 말했었다.
그런데 어짜피 안도 바깥도 같은데 하나로만 사용할 수는 없을까? 하는데서 온 것이 제네릭이라는 것이다.
하지만 위에 말한대로 하나의 타입으로 만든다면 Object를 사용하면 되지않을까? 최상위 클래스니까?!
하지만 이 부분 때문에 타입 안정성에 침해된다.
public class Generic {
public Object plusReturnFunction(Object a,Object b) { ... }
}
지금 이 예시코드에서 블럭{ }은 안에 연산이 없기때문에 그렇지만
a와 b의 객체에 단한 연산자를 사용할때 두 타입이 다르다면 어떠한 타입으로 맞출 수 있는 것인가에 대한 문제이다.
이 객체들이 어떤 타입을 가지고있는지도 모르고, 형변환 또한 때에 따라 달라지고 매개변수로 들어오는 순서도 달라질텐데 이런 부분들이 합쳐진다면, 부수적인 코드가 늘어나게 된다는 것이다.
// 1.제네릭 클래스, 메소드에 사용가능
// <> 안에 들어가야할 타입 명시
public class Generic<T> { //T는 타입변수를 뜻함.
// 2. 내부 필드에 String 이런식으로
private T t;
// 3. method return 타입도 가능
public T get() {
return this.t;
}
public void set(T t) {
this.t = t;
}
public static void main(String[] args) {
Generic<String> stringGeneric = new Generic<>();
//인스턴스화에는 타입변수에 실제값을 넣어주어야함.
stringGeneric.set("Hello World");
String tValueTurnOutWithString = stringGeneric.get();
System.out.println(tValueTurnOutWithString);
}
}
위에 주석으로 달아놓았지만 밑에 main메소드를 설명하자면,
Generic의 타입변수를 String으로 지정하여 객체를 생성한 뒤에 private T t 또한 private String string 이런식으로 선언된 String 문자열에 hello world를 넣고 sout하는 것이라고 보면된다.
여기서 잠깐!
타입변수는 왜 T일까?
일종의 컨벤션이기때문에 원하는 변수로 넣어도 상관은 없지만 대부분이 T로 지정한다.
이와 함께 자주 사용하는 변수명은 T, U, V, E등이 있다.
public class Generic<T> { ... }
//1. 제네릭 클래스 : 원시타입
//원시타입 : 타입 파라미터를 명시하지 않고 사용하는 제네릭 타입
//인스턴스화 되지 않는 것을 의미.
Generic<String> stringGeneric = new Generic<>();
//2. <>사이 들어가는 변수명 T는 타입변수
static 멤버에 사용할 수 없다.
제네릭 배열을 생성 할 수 없다.
//1.
public class Generic<T, U, E> {
public E multiTypeMethod(T t, U u) { ... }
}
Generic<Long, Integer, String> instance = new Generic();
instance.multiTypeMethod(longVal, intVal);
//3.
public class ParkingLot<T extends Car> { ... }
ParkingLot<BMW> bmwParkingLot = new ParkingLot();
ParkingLot<Iphone> iphoneParkingLot = new ParkingLog(); // error!
다수의 타입변수를 사용할 수 있다.
다형성 즉 상속과 타입의 관계는 그대로 적용된다.
와일드 카드를 통해 제네릭 제한을 구체적으로 정할 수 있다.
<? extends T> : T와 그 자손들만 사용 가능<? super T> : T와 그 조상들만 가능<?> : 제한 없음메서드를 스코프로 제네릭을 별도로 선언할 수 있습니다.

// 또는 ..
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
public class Generic<T, U, E> {
// Generic<T,U,E> 의 T와 아래의 T는 이름만 같을뿐 다른 변수
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
}