javascript, python 과 같은 약타입 언어를 이용한다면 기본적으로 변수의 타입 지정없이 함수를 구현 가능하다.
public class Generic {
public Object plusReturnFunction(Object a,Object b) { ... }
}
java 안에서 객체는 Object Class 를 상속한다. 때문에 위와 같은 Object type 으로 변수를 정의한다면 파라미터를 전달하는데 문제가 되지는 않아 보인다.
하지만 이런 경우 타입 안정성이 침해 받게 된다. 두개 이상의 파라미터가의 타입이 다를 때 순서 로직에서 더 많은 코드를 작성하는 문제가 생기는 것이다.
제네릭 이란 데이터형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법 이다. <> 안에 들어갈 타입변수의 이름을 지정한다. 일종의 컨벤션으로 T로 지정한다. public class Generic<T> {
private T t;
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);
}
}
// Generic Class
public class Generic<T> { ... }
// T = 타입 변수
Generic<String> stringGeneric = new Generic<>();
Generic Class 를 원시 타입 이라고 부르는데 객체가 인스턴스화 되지 않는것을 의미한다.
Generic은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);
2. 다형성, 상속과 타입의 관계는 그대로 작용한다.
3. 와일드 카드 를 통해 제네릭의 제한을 정할 수 있다.
public class ParkingLot<T extends Car> { ... }
ParkingLot<BMW> bmwParkingLot = new ParkingLot();
ParkingLot<Iphone> iphoneParkingLot = new ParkingLog(); // error
Error 의 해결 방한으로 다음과 같다.
1. <? extends T> : T와 그 자손들만 사용 가능
2. <? super T> : T와 그 조상들만 가능
3. <?> : 제한 없음
4. 메서드를 스코프로 제네릭을 별도로 선언 가능하다.

static <T> void sort(List<T> list, Comparator<? super T> c){...}
<> 제네릭을 사용한 경우, 해당 메서드만 적용되는 타입변수를 선언 가능하다.static 메서드에 사용 가능한 것이다. public class Generic<T, U, E> {
// Generic<T,U,E> 의 T와 아래의 T는 이름만 같을뿐 다른 변수
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
}
T라도 메서드와 클래스의 타입변수는 서로 다른 변수이다. Java 의 Collection 은 interface 로 구성되어져 있다.
// 실제 java.util의 List 코드
public interface List<E> extends Collection<E> {
int size();
boolean isEmpty();
...
boolean addAll(Collection<? extends E> c);
boolean add(E e);
...
}
List 인터페이스는 제네릭 인터페이스 이다.
intellij에서ctrl + n을 누르고List를 입력하면java.util안의 구성된 내용을 볼 수 있다.
Wrapper 객체는 원시타입을 추상화 시키는 역할을 한다.
그림에서 보이듯이 원시타입의 변수의 경우 값 이상의 의미를 가지는경우 메모리 사용량과 같은 성능상의 이유로 기본값을 객체화 하는 Wrapper Class 를 이용한다.
Integer num = new Integer(17); // Boxing
int n = num.intValue(); // UnBoxing
// JDK 15 부터는 AutoBoxing 기능이 있다.
Character ch = 'X'; // AutoBoxing
char c = ch; // AutoUnBoxing
때문에 박싱해서 객체화된 원시값들은 클래스처럼, 구현되어 있는 메서드를 사용 가능한 것이다. 즉 객체만 할 수 있는 기능을 사용가능한 것이다.
이번시간에는 제네릭에 대한 활용법과 java.util 에 들어있는 Collection 기능들을 이해할 수 있었다. 다음시간에는 Thread 에 대해 알아본다.