Comment expliquer ce comportement apparemment variable de varargs Java?

Si j’écris la méthode Java

public static void f(int... x) { for (int a: x) { System.out.println(a); } } 

alors je peux appeler cette méthode via

 f(1, 2, 3); 

aussi bien que

 f(new int[]{1, 2, 3}); 

et les deux appels sont traités exactement de la même manière. Cependant, les deux appels

 Arrays.asList(1, 2, 3) // (a) produces a three-element Integer list 

et

 Arrays.asList(new int[]{1, 2, 3}) // (b) produces a one-element list of Integer arrays 

ne sont pas traités de la même façon. La section sur l’évaluation des arguments dans le JLS indique “Le paramètre formel final de m a nécessairement le type T[] pour certains T “, alors pourquoi n’est-il pas le “paramètre formel final” dans le cas (b) ci-dessus, pas un tableau entier qui créerait une liste à trois éléments, comme le cas (a)?

La seule chose à laquelle je peux penser est que Arrays.asList est générique et que quelque chose à propos de la compatibilité des types (mentionné dans la section 15.12.4.2 de JLS) est en jeu ici, mais je ne peux pas vraiment mettre le doigt sur la phrase dans le JLS. cela rend les deux cas différents.

Le commentaire dans le JLS parle de la nécessité d’élaborer soigneusement cette sémantique afin de gérer l’interaction entre “les types paramétrés et les types de tableaux qui se produisent dans une machine virtuelle Java avec des génériques effacés”, mais nous aboutissons à ma fonction f et Arrays.asList semblant se comporter de manière incohérente. Dans le premier cas, je peux “décompresser” ou “emballer” mes arguments et tout est identique; dans ce dernier cas, les deux cas sont différents.

Comment cela s’explique-t-il en termes de juriste?

Arrays.asList est défini comme ayant le paramètre T... , et le corps le verra comme un argument de type T[] . Cependant, T doit être un type de référence (comme tout paramètre de type) et int n’est pas un type de référence. À cause de cela, il n’y a aucun moyen de rendre le new int[]{...} compatible avec un tableau à des fins de varargs. (Et le résultat serait List ce qui n’est pas autorisé.) La seule alternative est de le traiter comme un object unique, et donc T sera int[] , qui est un type de référence, et la fonction retournera une List .

Je pense que c’est la raison, bien que j’aurais encore besoin de rechercher le langage exact. Cela implique probablement les règles d’inférence de type, que je n’ai pas maîsortingsées.

Cependant, j’ai essayé ceci:

 List x = Arrays.asList(new int[]{1, 2, 3}); List y = Arrays.asList(new Integer[]{1, 2, 3}); System.out.println(x.size()); System.out.println(y.size()); 

(notez que j’ai délibérément utilisé un type brut, quelque chose que je ne ferais pas dans un code réel). Le résultat:

 1 3 
  Arrays.asList(1, 2, 3); 

1 2 3 sont automatiquement liés aux objects Integer qui sont ensuite placés dans un object []

  Arrays.asList(new int[]{1, 2, 3}); 

force les 3 entiers dans un tableau int primitif.

Arrays.asList() attend Object[] , il place donc votre tableau int[] dans un seul élément Object[]