본문은 Effective Java를 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
선결론
- varagrs 매개변수에 제네릭이나 매개변수화 타입이 포함되면 컴파일 경고가 발생한다
- 따라서 제네릭이나 매개변수화 타입이 포함된 varargs 매개변수를 사용하고자 한다면, 타입 안전 여부를 확인한 후 @SafeVarargs 애너테이션을 달도록 한다
가변인수 메서드와 제네릭
1. 가변인수와 제네릭은 궁합이 좋지 않다
- 가변인수 메서드를 호출하면 가변인수를 담기 위한 배열이 자동으로 하나 만들어진다
- 거의 모든 제네릭과 매개변수화 타입은 실체화 되지 않으며, 실체화 불가 타입은 런타임에는 컴파일타임보다 타입 관련 정보를 적게 담고 있다(아이템 28)
- 앞서 아이템28에서 배열과 제네릭은 궁합이 좋지 않다고 소개된 바 있다
2. 실제로 varagrs 매개변수에 실체화 불가 타입이 포함되면 컴파일 경고가 발생한다.
- 메서드를 선언할 때 실체화 불가 타입으로 varargs 매개변수를 선언하면 컴파일러가 경고를 보낸다
- 가변인수 메서드를 호출할 때도 varargs 매개변수가 실체화 불가 타입으로 추론되면, 그 호출에 대해서도 힙오염에 대한 경고를 낸다
- 힙오염
- 매개변수화 타입의 변수가 타입이 다른 객체를 참조하는 것을 힙 오염이라고 한다
힙 오염 예제
// https://www.geeksforgeeks.org/what-is-heap-pollution-in-java-and-how-to-resolve-it/
class Geeks {
public static void main(String[] args)
{
List<String> listOfString = new ArrayList<>();
listOfString.add("Geeksforgeeks");
List<Integer> listOfInteger = (List<Integer>)(Object)listOfString; // 힙 오염 발생
Integer firstElement = listOfInteger.get(0); // ClassCastException
System.out.println(firstElement);
}
}
- 힙 오염 발생
- 매개변수화 타입의 변수(listOfInteger)가 타입이 다른 객체(listOfString)을 참조함
3. 제네릭 varargs 매개변수를 사용함으로써 생성되는 제네릭 배열
- 아이템28에서 프로그래머가 직접 제네릭 배열을 생성하는 것은 허용되지 않는다고 소개한 바 있다
- 제네릭 varargs 매개변수를 받는 메서드를 허락한 이유는 제네릭이나 매개변수화 타입의 varargs 매개변수를 받는 메서드가 실무에서 매우 유용하기 때문이다
- Arrays.asList(T... a), Collections.addAll(Collection<? super T> c, T... elements), EnumSet.of(E first, E... rest) 등
- 위의 메서드들은 예제와 달리 타입 안전하다
@SafeVarargs 애너테이션
1. @SafeVarargs 애너테이션은 메서드 작성자가 타입 안전함을 보장하는 장치이다
- 자바 7에서는 @SafeVarargs 애너테이션이 추가되어 제네릭 가변인수 메서드 작성자가 클라이언트 측에서 발생하는 경고를 숨길 수 있게 되었다
- 컴파일러는 이 어노테이션을 믿고 그 메서드가 안전하지 않을 수 있다는 경고를 더 이상 하지 않는다
- 따라서 메서드가 안전한 게 확실치 않다면 절대 @SafeVarargs 애너테이션을 사용해서는 안 된다
- 또한, @SafeVarargs 애너테이션은 재정의할 수 없는 메서드에만 달아야 한다
- 재정의한 메서드도 안전할 지 여부는 보장할 수 없기 때문이다
2. 안전한 제네릭 varargs 메서드를 만드는 방법
- 1) varargs 매개변수 배열에 아무것도 저장하지 않는다
- 2) varargs 매개변수 배열의 참조가 밖으로 노출되지 않게 한다
- 이는, 신뢰할 수 없는 코드가 배열에 접근할 수 없도록 한다는 의미이다
- 두 가지의 예외에 한해 제네릭 varargs 매개변수 배열에 대한 참조를 허용한다
- 1) @SafeVarargs로 제대로 애노테이트된 또 다른 varargs 메서드에 넘기는 것은 안전하다
- 2) 그저 이 배열 내용의 일부 함수를 호출만 하는 (varargs를 받지 않는) 일반 메서드에 넘기는 것도 안전하다
'책 > Effective Java' 카테고리의 다른 글
[이펙티브 자바] 아이템 42: 익명 클래스보다는 람다를 사용하라 (0) | 2022.06.10 |
---|---|
[이펙티브 자바] 아이템 38: 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라 (0) | 2022.06.03 |
[이펙티브 자바] 아이템 30: 이왕이면 제네릭 메서드로 만들라 (0) | 2022.05.20 |
[이펙티브 자바] 아이템 28: 배열보다는 리스트를 사용하라 (0) | 2022.05.17 |
[이펙티브 자바] 아이템 27: 비검사 경고를 제거하자 (0) | 2022.05.13 |