import java.lang.reflect.Array;
public class PrimitiveArrayGeneric {
static <T> T[] genericArrayNewInstance(Class<T> componentType) {
return (T[]) Array.newInstance(componentType, 0);
}
public static void main(String args[]) {
int[] intArray;
Integer[] integerArray;
intArray = (int[]) Array.newInstance(int.class, 0);
// Okay!
integerArray = genericArrayNewInstance(Integer.class);
// Okay!
intArray = genericArrayNewInstance(int.class);
// Compile time error:
// cannot convert from Integer[] to int[]
integerArray = genericArrayNewInstance(int.class);
// Run time error:
// ClassCastException: [I cannot be cast to [Ljava.lang.Object;
}
}
J'essaie de comprendre complètement comment les génériques fonctionnent en Java. Les choses deviennent un peu bizarres pour moi dans la troisième affectation dans l'extrait ci-dessus: le compilateur se plaint que Integer[]
ne peut pas être converti en int[]
. La déclaration est 100% vrai, bien sûr, mais je me demande POURQUOI le compilateur fait cette plainte.Comportement bizarre à la compilation lors de la tentative d'utilisation du type primitif dans les génériques
Si vous commentez cette ligne, et suivez la "suggestion" du compilateur comme dans la 4ème affectation, le compilateur est réellement satisfait !!!maintenant le code se compile très bien! Ce qui est fou, bien sûr, puisque comme le comportement de temps d'exécution suggère, int[]
ne peut pas être converti en Object[]
(qui est ce que T[]
est effacé lors de l'exécution).
Donc ma question est: pourquoi le compilateur "suggère" que j'attribue à Integer[]
à la place pour la 3ème affectation? Comment le compilateur raisonne-t-il pour arriver à cette conclusion (erronée!)?
Il y a beaucoup de confusion dans les deux réponses à ce jour, donc je créé un autre exemple déconcertant pour illustrer la question sous-jacente:
public class PrimitiveClassGeneric {
static <T extends Number> T test(Class<T> c) {
System.out.println(c.getName() + " extends " + c.getSuperclass());
return (T) null;
}
public static void main(String args[]) {
test(Integer.class);
// "java.lang.Integer extends class java.lang.Number"
test(int.class);
// "int extends null"
}
}
Suis-je le seul qui pense qu'il est absolument fou que le compilateur laisse compiler le code ci-dessus?
Il ne serait pas déraisonnable d'imprimer c.getSuperclass().getName()
dans le code ci-dessus, par exemple, puisque j'ai spécifié que T extends Number
. Bien sûr maintenant getName()
jettera NullPointerException
quand c == int.class
, depuis c.getSuperclass() == null
.
Et pour moi, c'est une très bonne raison de rejeter le code de la compilation en premier lieu.
Peut-être la folie ultime:
int.class.cast(null);
Ce code se compile ET fonctionne bien.
Je peux me tromper mais je pense que techniquement 'int' n'a pas de classe mais quand vous utilisez' int.class' les boîtes de compilateur 'int' à' Integer' –
@ matt-b, int.class est une classe _real_. Vérifiez le javadoc pour Class.isPrimitive. Il a été autour depuis 1.1. Bien avant la boxe. Integer.class! = Int.class. Entier.TYPE == int.class. – nicerobot
"Le type de' int.class' est 'Classe' "- Je pense que la clé réside ici –
polygenelubricants