Java 5 부터 지원하기 시작한 기능이다.
직역하면 "일반화" 라고 부를 수 있는데 Cast Exception 과 같은 객체 유형의 혼용에 따른 에러를 방지하기위해
미리(컴파일) 점검하고자 만들어진 기능이다.
1. 제네릭스의 장점
- 유형의 추상화를 제공한다.
: 구체적인 유형을 지정하지 않고 추상유형을 사용하여 정의할 수 있다.
- 유형의 안정성을 제공한다.
: 의도하지 않은 유형의 객체를 저장하는 것을 막고,
저장된 객체를 가져올때 다른 형의로의 형변환에 따라 발생할 수 있는 오류를 줄여준다.
- 코드의 간결성을 제공한다.
: 유형체크와 형변환을 생략할 수 있으므로 코드가 간결해 진다.
제네릭스 문법을 알고 있다는 가정하에 기존의 코드양이 줄어든다.(문법을 모른다면 가독성이 떨어진다.)
[변경의 낡은 개발자 넋두리]
Java는 하위 호환성을 지원한다. 자바가 버전업 되어 Java 9에 이르지만 실제로는 1.9.x 이므로 이전의 문법으로 코딩했다면 1.9에서 작업 되었더라도 이전 컴파일러로 컴파일이 가능하면 이전 JVM에서 구동도 된다.
예전에 새버전 문법으로 작성했다가 고객사의 환경이 이전버전이어서 전부 수정한 경험이 있었다. 그래서 되도록이면 새로나온 문법과 기능이 좋더라도 호환성을 위해서 이전의 문법을 고수하였다. 그러나 세월도 흘러 Sun에서 Oracle로 바뀌었고 이후에 Java도 7, 8, 9 까지 나왔다. 요즘은 고객사의 시스템들도 대부분 5 이상을 사용한다. (간혹 4 버전의 고객이 있긴하다. ㅡ.ㅡ;;;) 이미 제네릭스나 어노테이션은 일반적인(범용적인) 문법이라고 봐도 무방할 것이다.
2. 제네릭스의 선언(define)
클래스나 메서드에서 제네릭 유형(type)을 선언해 줄 수 있는데 이는 내부에서 해당 제네릭 유형의 속성을 사용하겠다는 선언이다.
(내부에서 제네릭 유형이 사용됨을 선언)
- '<','>' 사이에 클래스내에서 사용할 제네릭 유형들을 ','로 구분해서 선언한다.
- 클래스와 메서드에 사용될 수 있으며 클래스는 클래스명 다음에 메서드는 반환유형 앞에 선언한다.
(메서드의 경우 입력파라메터-아규먼트 에 제너릭 유형을 사용하면 제너릭 메서드로 선언해 줘야 한다.)
- 제네릭에 사용되는 유형의 형식은 임으로 지정할 수 있으나 다음과 같이 범용적인 의미로 사용하는 유형들을 권고하고 있다.
E: 요소(Element, 자바 컬렉션 에서 주로 사용)
K: 키
N: 숫자
T: 타입
V: 값
S,U,V: 1개 이상 사용될 경우 두번째, 세번째, 네번쨰에 선언
public class Car<T> { // 클래스 선언
public <T> void setInfo(T t){ // 메서드 선언
......
}
}
public class Book<T, S>{ // 클래스에 1개 이상 선언
public T info(){
......
}
public S getIndex(){
......
}
}
3. 와일드카드(wildcard)
제너릭스 유형을 사용하여 파라메터를 지정할 경우 모든 유형에대하여 사용가능 하도록 사용하는 것이 와일드카드 이다.
- '?' 로 표시한다.
/**
* 제네릭스 클래스
*/
public class Test<T> {
......
}
/**
* 제네릭스 사용
*/
public class Sample {
public void use(Test<String> test){ // String 유형만 사용가능하다.
......
}
public void use2(Test<?> test){ // 모든유형이 사용가능하다.
......
}
}
4. 와일드 카드를 활용한 제한
와일드 카드를 사용하여 제너릭 유형의 범위를 제한할 수 있다.
- <? super 유형> : 명시된 유형의 상위객체만을 사용할 수 있다.
- <? extends 유형> : 명시된 유형의 상속객체 만을 사용할 수 있다.
* 참고서적 : 이상민. (2013). 자바의 신. 로드북