나는 일반적인 유형의 varargs를 사용할 때 Java 7에서 발생한다는 것을 이해합니다.
하지만 내 질문은 ..
"사용하면 잠재적으로 힙을 오염시킬 수있다"고 말할 때 Eclipse는 정확히 무엇을 의미합니까?
과
새로운 @SafeVarargs
주석은 어떻게 이것을 방지합니까?
Possible heap pollution from parameterized vararg type
나는 일반적인 유형의 varargs를 사용할 때 Java 7에서 발생한다는 것을 이해합니다.
하지만 내 질문은 ..
"사용하면 잠재적으로 힙을 오염시킬 수있다"고 말할 때 Eclipse는 정확히 무엇을 의미합니까?
과
새로운 @SafeVarargs
주석은 어떻게 이것을 방지합니까?
Possible heap pollution from parameterized vararg type
답변:
힙 오염은 기술 용어입니다. 가리키는 객체의 상위 유형이 아닌 유형을 가진 참조를 나타냅니다.
List<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As
이것은 "설명 할 수없는"을 초래할 수 있습니다 ClassCastException
.
// if the heap never gets polluted, this should never throw a CCE
B b = listOfBs.get(0);
@SafeVarargs
이것을 막지 않습니다. 그러나 아마도 힙을 오염시키지 않는 방법이 있습니다. 컴파일러는 단지 그것을 증명할 수 없습니다. 이전에는 이러한 API를 호출 한 사람에게는 완전히 무의미하지만 모든 호출 사이트에서 억제해야하는 성가신 경고가 표시되었습니다. 이제 API 작성자는 선언 사이트에서 한 번 억제 할 수 있습니다.
이 방법은 실제로 그러나, 하지 안전, 사용자는 더 이상 경고되지 않습니다.
선언 할 때
public static <T> void foo(List<T>... bar)
컴파일러는 그것을
public static <T> void foo(List<T>[] bar)
다음에
public static void foo(List[] bar)
그러면 목록에 잘못된 값을 잘못 할당하면 컴파일러에서 오류가 발생하지 않을 위험이 있습니다. 예를 들어, T
is String
이면 다음 코드는 오류없이 컴파일되지만 런타임에 실패합니다.
// First, strip away the array type (arrays allow this kind of upcasting)
Object[] objectArray = bar;
// Next, insert an element with an incorrect type into the array
objectArray[0] = Arrays.asList(new Integer(42));
// Finally, try accessing the original array. A runtime error will occur
// (ClassCastException due to a casting from Integer to String)
T firstElement = bar[0].get(0);
이러한 취약점을 포함하지 않는 방법을 검토 한 경우 @SafeVarargs
경고를 표시 하지 않도록 주석을 추가 할 수 있습니다 . 인터페이스의 경우을 사용하십시오 @SuppressWarnings("unchecked")
.
이 오류 메시지가 표시되면
Varargs 방법으로 수정할 수없는 varargs 매개 변수에서 힙 오염이 발생할 수 있음
그리고 당신은 당신의 사용법이 안전하다는 것을 확신하고 @SuppressWarnings("varargs")
대신에 사용해야 합니다. @SafeVarargs가이 방법에 적합한 주석입니까?를 참조하십시오 . 및 https://stackoverflow.com/a/14252221/14731 오류의 두 번째 종류의 좋은 설명합니다.
참고 문헌 :
Object[]
. 에 캐스팅하지 않는 한 Object[]
괜찮을 것 같습니다.
static <T> void bar(T...args) { ((Object[])args)[0] = "a"; }
있습니다. 그런 다음로 전화하십시오 bar(Arrays.asList(1,2));
.
Object[]
컴파일러가 경고 메시지를 표시하지 않으면 왜 경고를 트리거합니까? 결국 컴파일 타임에이를 확인하는 것이 상당히 쉬워야합니다 (유사한 서명이있는 다른 함수에 전달하지 않으면 다른 함수가 경고를 트리거해야합니다). 나는 이것이 정말로 경고의 핵심이라고 생각하지 않으며 ( "주조하지 않으면 안전하다"), 나는 어떤 경우에 나는 괜찮은지를 여전히 이해하지 못한다.
bar(Integer...args)
. 그렇다면이 경고의 요점은 무엇입니까?
@SafeVarargs
이를 방지하지는 않지만 컴파일러는이를 사용하는 코드를 컴파일 할 때 더 엄격해야합니다.
http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html 에서 자세히 설명합니다.
힙 오염은 ClassCastException
일반 인터페이스에서 작업을 수행 할 때 발생하는 것으로 선언 된 것과 다른 유형을 포함합니다.
varargs를 사용하면 Object[]
하면 인수를 보유 .
이스케이프 분석으로 인해 JIT는이 어레이 생성을 최적화 할 수 있습니다. (내가 찾은 몇 번 중 하나) 최적화되지는 않지만 메모리 프로파일 러에 문제가 없으면 걱정하지 않아도됩니다.
AFAIK @SafeVarargs
는 컴파일러의 경고를 표시하지 않으며 JIT의 작동 방식을 변경하지 않습니다.
@SafeVarargs
.
그 이유는 varargs가 매개 변수화되지 않은 객체 배열로 호출되는 옵션을 제공하기 때문입니다. 따라서 타입이 List <A> ...이면, Varargs가 아닌 List [] 타입으로도 호출 할 수 있습니다.
예를 들면 다음과 같습니다.
public static void testCode(){
List[] b = new List[1];
test(b);
}
@SafeVarargs
public static void test(List<A>... a){
}
보시다시피 List [] b는 모든 유형의 소비자를 포함 할 수 있지만이 코드는 컴파일됩니다. varargs를 사용하면 괜찮지 만 유형 삭제 후 메소드 정의를 사용하면 void test (List [])-컴파일러는 템플릿 매개 변수 유형을 확인하지 않습니다. @SafeVarargs는이 경고를 표시하지 않습니다.