티스토리 뷰
1. 제네릭스란?
제네릭스는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에서 컴파일 시 타입체크(compile-time type check)를 해주는 기능이다.
예를들어, ArrayList와 같은 컬렉션 클래스는 다양한 종류의 객체를 담을 수 있긴 하지만 보통 한 종류의 객체를 담는 경우가 더 많다.
그런데도 데이터를 꺼낼 때 마다 타입체크를 하고 형변환을 하는 것은 불편할 수 밖에 없다.
또한 원하지 않는 종류의 객체가 포함될 가능성도 있다.
이러한 문제들을 제네릭스가 해결해 준다.
즉, 다룰 객체의 타입을 미리 명시해줌으로써 번거로운 형변환을 줄여준다.
제네릭스의 장점
1. 타입 안정성을 제공한다.
2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 진다.
2. 제네릭 클래스의 선언
제네릭 타입은 클래스와 메서드에 선언할 수 있다.
ex) 제네릭 클래스 선언
class Box<T> {
T item;
void setItem(T item) { this.item = item; }
T getItem() { return item; }
}
위의 예제에서 T를 '타입 변수(type variable)' 라고 한다.
타입변수는 T가 아닌 다른 것을 사용해도 된다.
ex) ArrayList<E>, Map<K, V>
즉, T, E, K, V 등은 기호의 종류만 다를 뿐 '임의의 참조형 타입'을 의미한다는 것은 모두 같다.
Box<T> 와 캍이 타입변수를 선언해 주면 어떤 타입이든 한 가지 타입을 정해서 담을 수 있다.
※ 제네릭스 용어
class Student<T> {}
- Student<T> : 제네릭 클래스. 'T의 Student' 또는 'T Student' 라고 읽는다.
- T : 타입 변수 또는 타입 매개변수. (T는 타입 문자)
- Student : 원시 타입 (raw type)
컴파일 후에 Student<String> 과 String<Integer> 등은 이들의 '원시타입' 인 Student로 바뀐다.
(즉, 제네릭 타입이 제거된다.)
제네릭스의 제한
static 멤버에는 타입변수 T를 사용할 수 없다. T는 인스턴스 변수로 간주되기 때문이다.
(또한 static 멤버는 대입된 타입의 종류에 관계없이 동일한 것이어야 하기 때문이다.)
또한 new 연산자를 이용하여 제네릭 타입의 배열을 생성하는 것도 허용되지 않는다.
(제네릭 클래스를 컴파일 하는 시점에는 T가 어떤 타입이 될 지 전혀 알 수 없기 때문이다.)
class Box<T> {
staitc T item; // 에러
static int compare(T t1, T t2 { ... } // 에러
T[] itemArr; // 가능. T타입의 배열을 위한 참조변수의 선언은 가능
T[] toArray() {
T[] tmpArr = new T[itemArr.length]; // 에러. 제네릭 배열 생성 불가
...
return tmpArr;
}
}
제한된 제네릭 클래스
타입 문자로 사용할 타입을 명시하면 (Box<String>) 한 종류의 타입만 저장할 수 있도록 제한할 수 있지만,
그래도 여전히 모든 종류의 타입을 지정할 수 있다는 것에는 변함이 없다.
이럴때 제네릭 타입에 'extends'를 사용하면, 특정 타입의 자손들만 대입할 수 있게 제한할 수 있다.
만약 클래스가 아니라 인터페이스를 구현해야 한다는 제약이 필요하다면, 이때도 'extends' 를 사용한다.
('implement'를 사용하지 않는 다는 점에 주의해야 한다.)
interface Eatable {}
class FruitBox<T extends Eatable> { ... } // 인터페이스를 구현한 클래스만 T로 허용
class FruitBox<T extends Fruit & Eatable> { ... } // 인터페이스를 구현하고 Fruit를 상속한 클래스만 T로 허용
3. 와일드 카드
와일드 카드는 기호 '?' 로 표현하고, 와일트 카드는 어떠한 타입도 될 수 있다.
'?' 만으로는 Object 타입과 다른 것이 없으므로, 'extends'와 'super'로 상한(upper bound)과 하한(lower bound)를 제한할 수 있다.
<? extends T> 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? extends T> 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> 제한 없음. 모든 타입이 가능. (<? extends Object>와 동일)
4. 제네릭 메서드
메서드의 선언부에 제네릭 타입이 선언된 메서드를 제네릭 메서드라고 한다.
Collections.sort() 가 바로 대표적인 제네릭 메서드이다.
제네릭 타입의 선언 위치는 반환타입 바로 앞이다.
제네릭 클래스에 정의된 타입 매개변수와 제네릭 메서드에 정의된 타입 매개변수는 전혀 별개의 것이다.
제네릭 메서드는 제네릭 클래스가 아닌 클래스에서도 정의될 수 있다.
class FruitBox<T> {
...
static <T> void sort(List<T> list, Comparator<? super T> c) {
...
}
}
기본적으로, static 멤버에는 타입 매개변수를 사용할 수 없지만, 메서드에 제네릭 타입을 선언하고 사용하는 것은 가능하다.
메서드에 선언된 제네릭 타입은 지역변수를 선언한 것과 같다고 이해하면 쉽다.
즉, 메서드에 선언된 타입 매개변수는 메서드 내에서만 지역적으로 사용될 것이므로 메서드가 static이건 아니건 상관이 없다.
참고자료
남궁 성 지음, 자바의 정석, 도우출판
'프로그래밍 언어 > Java' 카테고리의 다른 글
람다식(Lambda expression) (0) | 2019.06.23 |
---|---|
열거형 (0) | 2019.06.20 |
컬렉션 프레임워크 (0) | 2019.06.18 |
java.lang 패키지 (0) | 2019.06.17 |
예외처리 (0) | 2019.06.17 |
- Total
- Today
- Yesterday
- 상속
- 싱글톤 레지스트리
- 람다식
- 스프링
- 리버스 프록시
- 전자정부프레임워크
- stateless
- 가상 회선 방식
- 스프링부트
- 유효성검사
- 회원가입
- 클래스
- 객체
- Servlet
- AJAX
- 제네릭 메서드
- 자바의 정석
- github
- git
- 웹 서버
- 스프링 부트 시큐리티
- 인텔리제이
- 멀티 프로세스
- http
- JVM 메모리 구조
- 포워드 프록시
- 그래프 순회 알고리즘
- jvm
- connectionless
- 메서드 참조
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |