- [Java 정리] Generics2022년 04월 09일
- starryeye
- 작성자
- 2022.04.09.:00
Generics
다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스를 컴파일 시점에 타입 체크를 해주는 기능
객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어듬
(generic 타입은 컴파일러가 컴파일할 때만 사용하고 제거)
Generics의 장점
1. 타입 안정성을 제공
2. 타입 체크와 형변환을 생략할 수 있으므로 코드가 간결해짐
-> 객체의 타입을 미리 명시해줘서 번거로운 형변환을 줄여준다.
Generic Class 선언
class Box<T> { T item; void setItem(T item) { this.item = item; } T getItem() { return item; } }
// generic type T 선언
T : 타입 변수
Generic Class인 Box Class의 객체 생성
Box<String> b = new Box<String>();
위 와 같이 참조변수와 생성자에 실제 타입을 지정해준다.
용어
class Box<T> {}
Box<T> : generic class, T box라 부름
T : 타입 변수, 타입 매개변수
Box : 원시 타입
제한
class Box<T> { static T item; //err1 static int compare(T t1, T t2) {} //err2 T[] itemArr; //OK1 T[] getArray() { T[] tmpArr = new T[itemArr.length]; //err3 } }
위 코드는 컴파일에러가 발생한다.
T는 인스턴스 변수로 간주되기 때문에 static 맴버에 타입 변수 T를 사용 할 수 없다.(err1, err2)
generic 배열 타입의 참조 변수를 선언하는건 가능(ok1)
하지만, 배열을 직접 생성하는건 불가능.(err3)
-> (new 연산자때문임, new연산자는 컴파일 시점에 타입 T가 뭔지 정확히 알아야 함. 컴파일 시점에 이 코드만 놓고는 T가 어떤 타입인지 모르자나)err3 방법>
1. new 연산자 대신 Reflection API의 newInstance() 를 사용하여 동적으로 객체 생성
2. Object 배열을 생성하여 T[]로 형변환하여 복사
Generic 메서드
class FruitBox<T> { ... static <T> void sort(List<T> list, Comparator<? super T> c) { ... } }
static 맴버에는 타입 매개 변수를 사용할 수 없지만, 메서드에 generic 타입을 선언하고 사용하는 것은 가능
(참고로 클래스에 선언된 T와 메서드에 선언된 T는 문자만 같을 뿐 서로 다른것이다.)
public static <T extends Comparable<? super T>> void sort(List<T> list)
List<T> : 타입 T를 요소로 하는 List를 매개변수로 허용
T extends Comparable : T는 Comparable을 구현한 클래스
Comparable<? super T> : T 또는 그 조상의 타입을 비교하는 Comparable이어야 함
형변환 + 라이브러리 읽기
java.util.Optional
public final class Optional<T> { ... private static final Optional<?> EMPTY = new Optional<>(); private final T value; ... public static<T> Optional<T> empty() { Optional<T> t = (Optional<T>) EMPTY; return t; } ... }
<?>는 <? extends Object>를 줄여 쓴 것
<>안에 생략된 타입은 Object 이다.
EMPTY 타입을 Optional<Object>가 아닌 Optional<?>로 한 이유는 Optional<T>로 형변환이 가능하기 때문이다.
Optional<?> wopt = new Optional<Object>(); Optional<Object> oopt = new Optional<Object>(); Optional<String> sopt = (Optional<String>)wopt; //OK Optional<String> sopt = (Optional<String>)oopt; //err
wopt : Object --> ? --> String
oopt : Object --> String
empty()의 반환 타입이 Optional<T> 이므로 EMPTY를 Optional<T>로 형변환해야 하는데, 위의 코드 처럼 Optional<T>로 형변환 불가능함
<정리>
Optional<Object>를 Optional<String>으로 직접 형변환 불가능
와일드 카드가 포함된 genericc 타입으로 형변환하면 가능
Optional<Object> --> Optional<T> // 불가능
Optional<Object> --> Optional<?> --> Optional<T> // 가능
읽어보면 좋은 포스팅
'Java' 카테고리의 다른 글
[Java 정리] Garbage Collector 1 (0) 2022.07.30 [Java 정리] 내부 클래스 (0) 2022.07.28 [Java 정리] Exception, Error (0) 2022.07.15 [Java 정리] Annotation (0) 2022.04.09 [Java 정리] enum (0) 2022.04.09 다음글이전글이전 글이 없습니다.댓글