Potencjalne zanieczyszczenie hałdy przez parametr varargs

Rozumiem, że występuje to w Javie 7, gdy używa się varargs z typem generycznym;

Ale moje pytanie brzmi:.

Co dokładnie oznacza Eclipse, gdy mówi " jego użycie może potencjalnie zanieczyścić stertę?"

I

Jak nowa adnotacja @SafeVarargs temu zapobiega?

Author: MarmiK, 2012-09-17

5 answers

Zanieczyszczenie hałdy to termin techniczny. Odnosi się do odniesień, które mają typ, który nie jest supertyp obiektu, do którego wskazują.

List<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As

To może prowadzić do "niewytłumaczalnych" ClassCastExceptions.

// if the heap never gets polluted, this should never throw a CCE
B b = listOfBs.get(0); 

@SafeVarargs nie zapobiega to w ogóle. Istnieją jednak metody, które w sposób udowodniony nie zanieczyszczą sterty, kompilator po prostu nie może tego udowodnić. Wcześniej osoby wywołujące takie API otrzymywały irytujące ostrzeżenia, które były całkowicie bezcelowe, ale musiały być tłumione na każdej stronie wywołania. Teraz Autor API może go raz wyłączyć na stronie deklaracji.

Jednakże, jeśli metoda rzeczywiście jest nie bezpieczna, użytkownicy nie będą już ostrzegani.

 209
Author: Ben Schulz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-17 15:16:02

Kiedy zadeklarujesz

public static <T> void foo(List<T>... bar) kompilator konwertuje go do

public static <T> void foo(List<T>[] bar) następnie do

public static <T> void foo(List[] bar)

Pojawia się niebezpieczeństwo, że przez pomyłkę przypiszesz niepoprawne wartości do listy i kompilator nie uruchomi żadnego błędu. Na przykład, jeśli T jest String, to następujący kod zostanie skompilowany bez błędu, ale nie powiedzie się w czasie wykonywania:

// 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);

Jeśli sprawdziłeś metodę, aby upewnić się, że nie zawiera takich luk, możesz dodać do niej adnotację za pomocą @SafeVarargs aby stłumić Ostrzeżenie. W przypadku interfejsów użyj @SuppressWarnings("unchecked").

Jeśli otrzymasz ten Komunikat o błędzie:

Metoda Varargsa może powodować zanieczyszczenie sterty nieefektywnym parametrem varargsa

I jesteś pewien, że Twoje użycie jest bezpieczne, powinieneś zamiast tego użyć @SuppressWarnings("varargs"). Zobacz czy @ SafeVarargs jest odpowiednią adnotacją dla tej metody? i https://stackoverflow.com/a/14252221/14731 dla miłego wyjaśnienia tego drugiego rodzaju błąd.

Bibliografia:

 187
Author: Gili,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:47

@SafeVarargs nie przeszkadza to jednak, że kompilator jest surowszy podczas kompilacji kodu, który go używa.

Http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html wyjaśnia to bardziej szczegółowo.

Zanieczyszczenie sterty jest wtedy, gdy otrzymujemy ClassCastException podczas wykonywania operacji na interfejsie generycznym i zawiera on inny typ niż zadeklarowany.

 7
Author: jontro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-17 15:14:33

Kiedy używasz varargs, może to spowodować utworzenie Object[] do przechowywania argumentów.

Ze względu na analizę ucieczki, JIT może zoptymalizować tworzenie tej tablicy. (Jeden z kilku razy znalazłem to robi) jego nie gwarantuje być zoptymalizowane daleko, ale nie martwiłbym się o to, chyba że widzisz jego problem w pamięci profiler.

AFAIK @SafeVarargs tłumi Ostrzeżenie kompilatora i nie zmienia zachowania JIT.

 5
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-17 15:37:46

Powodem jest to, że varargs daje możliwość wywołania z nieparametryzowaną tablicą obiektów. Więc jeśli twój typ był List ... , może być również wywołany z typem List [] non-varargs.

Oto przykład:

public static void testCode(){
    List[] b = new List[1];
    test(b);
}

@SafeVarargs
public static void test(List<A>... a){
}

Jak widać List [] b może zawierać dowolny typ konsumenta, a jednak kod ten kompiluje się. Jeśli używasz varargs, to jest dobrze, ale jeśli używasz definicji metody po type-erasure - void test(List []) - wtedy kompilator nie sprawdzi szablonu typy parametrów. @SafeVarargs stłumi to Ostrzeżenie.

 0
Author: user1122069,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-26 23:11:30