꼬물꼬물
[자바의 정석] Generics(제너릭스) 본문
- JDK 1.5에서 도입된 제너릭스
1.1 제너릭스란?
- 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시 타입 체크를 해주는 기능이다.
- 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.
- 장점
- 타입 안정성을 제공
- 타입 체크와 형변환을 생략할 수 있어 코드가 간결해진다.
예)
class Box<T>{
T item;
void setItem(T item) { this.item = item; }
T getItem() { return item; }
}
- <T>의 T는 타입변수(type variable)라고 하며, ‘T’ype에서 따온 것으로 다른 것을 사용해도 된다.
- ArrayList<E> : Element
- K: key
- V: value
- 기호의 종류만 다를 뿐, 임의의 참조형 타입을 의미한다.
- 용어
- Box<T>: 제너릭 클래스. T의 Box 혹은 T Box라고 읽는다.
- T: 타입 변수
- Box: 원시 타입
제너릭의 제한
- 객체 생성시 타입을 지정해줘야 한다.
- 예) Box<String> box = new Box<String>();
- 모든 객체에 대해 동일하게 동작해야하는 static 멤버에는 타입 변수를 사용할 수 없다.
- static 멤버는 타입 변수에 지정된 타입의 종류에 상관없이 동일한 것이어야 하기 때문이다.
- class Box<T>{ static T item; // 에러 static int compare(T t1, T t2) { ... } // 에러 }
- 제너릭 타입의 배열을 생성할 수 없다.
- 제너릭 배열 타입의 참조변수를 선언하는 것은 가능하지만 new T[10] 은 불가능하다.
class Box<T>{ T[] itemArr; // T 타입의 배열을 위한 참조변수, OK T toArray(){ T[] tmpArr = new T[itemArr.length]; // 에러, 제너릭 배열 생성불가. return tmpArr; } }- new 연산자는 컴파일 시점에 타입 T가 무엇인지 정확하게 알아야 한다.
- 그러나 위의 코드는 컴파일 시점에 어떤 타입이 될지 전혀 알 수 없다.
- instanceof 연산자도 같은 이유로 T를 피연산자로 사용할 수 없음.
- 꼭 제너릭 배열을 생성해야 한다면, new 연산자 대신, Reflection API의 newInstance()와 같이 동적으로 객체를 생성하는 메서드로 배열을 생성하거나
- Object로 배열을 생성해 복사한 다음 T로 형변환해 사용해야 한다.
1.6 제너릭 메서드
- 메서드 선언부에 제너릭 타입이 선언된 메서드를 제너릭 메서드라 한다.
- Collections.sort()가 제너릭 메서드
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
- 제너릭 클래스에서 정의된 타입 매개변수와 제너릭 메서드에 정의된 타입 매개변수는 전혀 다르다.
- 같은 타입문자 T를 사용해도 같은 것이 아니라는 것에 주의해야 한다.
- 제너릭 메서드는 제너릭 클래스가 아닌 클래스에도 정의될 수 있다.
class FruitBox<T> {
...
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
}
- 제너릭 클래스 FruitBox의 T와 제너릭 메서드 sort()에 선언된 타입 매개변수 T는 문자만 같을 뿐 서로 다른 것.
- sort()가 static인 것에 주목하자!
- static 멤버에는 타입 매개변수를 사용할 수 없지만, 메서드에는 제너릭 타입을 선언하고 사용할 수 있다.
- 메서드에 선언된 제너릭 타입은 지역 변수를 선언한 것과 같다고 생각하면 된다.
내가 사용한 제너릭 메서드
private <K, V> String keyValueString(HashMap<K, V> map) {
Object[] keySet = sortKey(map);
StringBuilder sb = new StringBuilder();
for (Object key: keySet){
sb.append(key).append(": ").append(map.get(key)).append("\n");
}
return sb.append("\n").toString()
}
private <K, V> Object[] sortKey(Map<K, V> map) {
Object[] keySet = map.keySet().toArray();
Arrays.sort(keySet);
return keySet;
}
추가
제너릭은 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정된다.
'스터디 > JAVA' 카테고리의 다른 글
| [자바의 정석]11. 컬렉션 프레임웍-2 (1) | 2022.10.29 |
|---|---|
| [자바의 정석]11. 컬렉션 프레임웍-1 (0) | 2022.10.27 |
| 다우기술 문제풀이 회고 (0) | 2022.10.26 |
| [자바의 정석] java.lang패키지와 유용한 클래스 (0) | 2022.10.14 |
| [자바의 정석] 6. 객체지향 프로그래밍 I (0) | 2022.10.06 |