[java] varargs 매개 변수를 통한 가능한 힙 오염

나는 일반적인 유형의 varargs를 사용할 때 Java 7에서 발생한다는 것을 이해합니다.

하지만 내 질문은 ..

“사용하면 잠재적으로 힙을 오염시킬 수있다”고 말할 때 Eclipse는 정확히 무엇을 의미합니까?

새로운 @SafeVarargs주석은 어떻게 이것을 방지합니까?



답변

힙 오염은 기술 용어입니다. 가리키는 객체의 상위 유형이 아닌 유형을 가진 참조를 나타냅니다.

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)

그러면 목록에 잘못된 값을 잘못 할당하면 컴파일러에서 오류가 발생하지 않을 위험이 있습니다. 예를 들어, Tis 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 오류의 두 번째 종류의 좋은 설명합니다.

참고 문헌 :


답변

@SafeVarargs 이를 방지하지는 않지만 컴파일러는이를 사용하는 코드를 컴파일 할 때 더 엄격해야합니다.

http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html 에서 자세히 설명합니다.

힙 오염은 ClassCastException일반 인터페이스에서 작업을 수행 할 때 발생하는 것으로 선언 된 것과 다른 유형을 포함합니다.


답변

varargs를 사용하면 Object[] 하면 인수를 보유 .

이스케이프 분석으로 인해 JIT는이 어레이 생성을 최적화 할 수 있습니다. (내가 찾은 몇 번 중 하나) 최적화되지는 않지만 메모리 프로파일 러에 문제가 없으면 걱정하지 않아도됩니다.

AFAIK @SafeVarargs는 컴파일러의 경고를 표시하지 않으며 JIT의 작동 방식을 변경하지 않습니다.


답변

그 이유는 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는이 경고를 표시하지 않습니다.


답변