Je comprends que cela se produit avec Java 7 lors de l'utilisation de varargs avec un type générique;
Mais ma question est ..
Que signifie exactement Eclipse quand il dit "son utilisation pourrait potentiellement polluer le tas?"
Et
Comment la nouvelle @SafeVarargs
annotation empêche-t-elle cela?
java
eclipse
generics
variadic-functions
hertzsprung
la source
la source
Possible heap pollution from parameterized vararg type
Réponses:
La pollution en tas est un terme technique. Il fait référence à des références dont le type n'est pas un sur-type de l'objet vers lequel elles pointent.
Cela peut conduire à des «inexplicables»
ClassCastException
.@SafeVarargs
ne l'empêche pas du tout. Cependant, il existe des méthodes qui ne pollueront pas le tas, le compilateur ne peut tout simplement pas le prouver. Auparavant, les appelants de ces API recevaient des avertissements ennuyeux qui étaient complètement inutiles mais devaient être supprimés sur chaque site d'appel. L'auteur de l'API peut désormais le supprimer une fois sur le site de déclaration.Cependant, si la méthode n'est pas sûre, les utilisateurs ne seront plus avertis.
la source
Lorsque vous déclarez
public static <T> void foo(List<T>... bar)
le compilateur le convertit enpublic static <T> void foo(List<T>[] bar)
puispublic static void foo(List[] bar)
Le danger survient alors que vous attribuerez par erreur des valeurs incorrectes dans la liste et que le compilateur ne déclenchera aucune erreur. Par exemple, si
T
est un,String
le code suivant se compilera sans erreur mais échouera au moment de l'exécution:Si vous avez examiné la méthode pour vous assurer qu'elle ne contient pas de telles vulnérabilités, vous pouvez l'annoter avec
@SafeVarargs
pour supprimer l'avertissement. Pour les interfaces, utilisez@SuppressWarnings("unchecked")
.Si vous obtenez ce message d'erreur:
et vous êtes sûr que votre utilisation est sûre, vous devez utiliser à la
@SuppressWarnings("varargs")
place. Voir @SafeVarargs une annotation appropriée pour cette méthode? et https://stackoverflow.com/a/14252221/14731 pour une belle explication de ce deuxième type d'erreur.Références:
la source
Object[]
. Tant que vous ne lancez pasObject[]
, il semble que vous devriez aller bien.static <T> void bar(T...args) { ((Object[])args)[0] = "a"; }
. Et puis appelezbar(Arrays.asList(1,2));
.Object[]
pourquoi le compilateur déclencherait-il un avertissement si je ne le fais pas? Cela devrait être assez facile à vérifier au moment de la compilation, après tout (dans le cas où je ne le passe pas à une autre fonction avec une signature similaire, auquel cas l'autre fonction devrait déclencher un avertissement). Je ne crois pas que ce soit vraiment le cœur de l'avertissement ("Vous êtes en sécurité si vous ne lancez pas"), et je ne comprends toujours pas dans quel cas je vais bien.bar(Integer...args)
). Alors quel est l'intérêt de cet avertissement alors?@SafeVarargs
ne l'empêche pas de se produire, mais il exige que le compilateur soit plus strict lors de la compilation du code qui l'utilise.http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html explique cela plus en détail.
La pollution de tas est lorsque vous obtenez un
ClassCastException
lors d'une opération sur une interface générique et qu'elle contient un autre type que celui déclaré.la source
Lorsque vous utilisez des varargs, cela peut entraîner la création d'un
Object[]
pour contenir les arguments.En raison de l'analyse d'échappement, le JIT peut optimiser cette création de tableau. (L'une des rares fois où je l'ai trouvé le fait) Ce n'est pas garanti d'être optimisé, mais je ne m'en inquiéterais pas à moins que vous ne voyiez un problème dans votre profileur de mémoire.
AFAIK
@SafeVarargs
supprime un avertissement du compilateur et ne change pas le comportement du JIT.la source
@SafeVarargs
.La raison en est que les varargs donnent la possibilité d'être appelés avec un tableau d'objets non paramétré. Donc, si votre type était List <A> ..., il peut également être appelé avec le type List [] non varargs.
Voici un exemple:
Comme vous pouvez le voir, List [] b peut contenir n'importe quel type de consommateur, et pourtant ce code se compile. Si vous utilisez des varargs, tout va bien, mais si vous utilisez la définition de méthode après l'effacement de type - test void (List []) - alors le compilateur ne vérifiera pas les types de paramètres de modèle. @SafeVarargs supprimera cet avertissement.
la source