가변인수:메서드에 넘기는 인수의 개수를 클라이언트가 조절할수있게 해준다.
가변인수 메서드를 호출하면 가변인수를 담기위한 배열이 생성됨
->varags 매개변수에 제네릭이나 변수화 타입이포함될시 컴파일 경고 발생
warning: [unchecked] Possible heap polluation from
parameterized vararg type List<String>
1.매개변수화 타입의 변수가 타입이 다른객체를 참조하면 힙 오염이 발생
static void dangerous(List<String>...stringLists)
List<Integer> intList=List.of(42);
Object[] objects=stringLists;
objects[0]= intList; //힙 오염 발생
String s= stringLists[00.get(0) //ClassCastException
=> 타입 안정성이깨지므로 제네릭 varags메서드열 매개변수에 값을 저장하는것은 안전하지않다.
3.가변인수 메서드를 호출할때 varargs매개변수를 담는 제네릭 배열이 만들어진다는 사실을 기억해야함!
=> 이때 varargs매개변수 배열에 아무것도 저장하지않고도 타입안정성을 깰수있으니 주의해야함
static<T> T[] toArray(T... args){
return args;
}
위코드에서는 자신의 제네릭 매개변수가 배열의 노출을 참조하므로 안전하지 않은 코드이다.
4.제네릭 varargs 매개변수를 안전하게 사용하는메서드
-> 제네릭이나 매개변수화 타입의 varargs매개변수를 받는 모든 메서드에 @SafeVarargs를 달라
-> 사용자를 헷갈리는 컴파일러 경고를 없앨수있다
@SafeVarargs
static <T> List<T> flatten(List<? extends T>...lists{
List<T> result= new ArrayList<>();
for(List<? extends T> list: lists)
result.addAll(list);
return result;
}
->varargs매개변수를 List매개변수로 바꿀수도있다
->List로 대체한 예
static <T> List<T> flatten(List<List<? extends T>>lists{
List<T> result= new ArrayList<>();
for(List<? extends T> list: lists)
result.addAll(list);
return result;
이 방식의 장점
1) 컴파일러가 메서드의 타입 안정성을 검증할수있다
2) @SafeVarargs 애너테이션 직접 달지않아도 된다
3) List.of를 활용하면 메서드에 임의개수 인수를 넘길수있다.
1)가변인수와 제네릭은 궁합이 좋지않다
-> 가변인수 기능은 배열을 노출하여 추상화가 완벽하지못하고, 배열과 제네릭의
타입 규칙이 서로 다르기 때문
2) 제네릭 varargs 매개변수는 타입이 안전하진 않지만 하용된다
-> 해당 변수를 사용하고자하면 먼저 그 메서드 타입이 안전한지 확인
@SafeVarargs 애너테이션을 달아서 사용불편을 줄이자