Quelles sont les différences entre List
, List<?>
, List<T>
, List<E>
et List<Object>
?
1. Liste
List
: est un type brut, donc non typesafe
. Il ne générera une erreur d'exécution que lorsque le casting est mauvais. Nous voulons une erreur de temps de compilation lorsque le cast est mauvais. Non recommandé à utiliser.
2. Liste <?>
List<?>
est un caractère générique illimité. Mais je ne sais pas à quoi ça sert? Je peux imprimer un List<?>
sans problème:
public static void test(List<?> list){
System.out.println(list); // Works
}
Pourquoi ne puis-je pas ajouter d'articles à un List<?>
?
public static void test(List<?> list){
list.add(new Long(2)); // Error
list.add("2"); // Error
System.out.println(list);
}
3. Liste <T>
public static void test(List<T> list){ // T cannot be resolved
System.out.println(list);
}
Je ne comprends pas cette syntaxe. J'ai vu quelque chose comme ça, et ça marche:
public <T> T[] toArray(T[] a){
return a;
}
Parfois, je vois <T>
, ou <E>
, ou <U>
, <T,E>
. Sont-ils tous identiques ou représentent-ils quelque chose de différent?
4. Liste <Objet>
Cela donne l'erreur "La méthode test(List<Object>)
n'est pas applicable pour l'argument List<String>
":
public static void test(List<Object> list){
System.out.println(list);
}
Si j'essaye ceci, je reçois "Impossible de lancer la diffusion List<String>
vers List<Object>
":
test((List<Object>) names);
Je suis confus. String
est une sous - classe de Object
, alors pourquoi n'est pas List<String>
une sous - classe List<Object>
?
2
. J'écris quelques codes pour le démontrer2
. tyvmList<Object>
-ils?Pour la dernière partie: Bien que String soit un sous-ensemble d'Object, mais List <String> n'est pas hérité de List <Object>.
la source
List<Object>
-ils?La notation
List<?>
signifie "une liste de quelque chose (mais je ne dis pas quoi)". Étant donné que le code danstest
fonctionne pour tout type d'objet dans la liste, cela fonctionne comme un paramètre de méthode formel.L'utilisation d'un paramètre de type (comme dans votre point 3), nécessite que le paramètre de type soit déclaré. La syntaxe Java pour cela est de mettre
<T>
en avant de la fonction. Ceci est exactement analogue à la déclaration de noms de paramètres formels à une méthode avant d'utiliser les noms dans le corps de la méthode.En ce qui concerne le fait de
List<Object>
ne pas accepter aList<String>
, cela a du sens parce que aString
ne l'est pasObject
; c'est une sous-classe deObject
. Le correctif est de déclarerpublic static void test(List<? extends Object> set) ...
. Mais alors leextends Object
est redondant, car chaque classe s'étend directement ou indirectementObject
.la source
List<Object>
-ils?List<?>
car la liste est d'un type spécifique mais inconnu.List<Object>
serait vraiment "une liste de tout" car elle peut en effet contenir n'importe quoi.La raison pour laquelle vous ne pouvez pas jeter
List<String>
àList<Object>
est qu'il vous permettra de violer les contraintes duList<String>
.Pensez au scénario suivant: si j'en ai un
List<String>
, il est censé ne contenir que des objets de typeString
. (Qui est unefinal
classe)Si je peux lancer cela sur un
List<Object>
, cela me permet d'ajouterObject
à cette liste, violant ainsi le contrat d'origine deList<String>
.Ainsi, en général, si la classe
C
hérite de la classeP
, vous ne pouvez pas dire qu'elleGenericType<C>
hérite également deGenericType<P>
.NB J'ai déjà fait des commentaires à ce sujet dans une réponse précédente, mais je voulais développer ce point.
la source
List<Object>
?List<Object>
car cela défait en quelque sorte le but des génériques. Cependant, il existe des cas où l'ancien code peut avoir unList
type différent acceptant, vous pouvez donc souhaiter adapter le code pour utiliser le paramétrage de type juste pour éviter les avertissements du compilateur pour les types bruts. (Mais la fonctionnalité est inchangée)Je conseillerais de lire les puzzles Java. Il explique assez bien l'héritage, les génériques, les abstractions et les caractères génériques dans les déclarations. http://www.javapuzzlers.com/
la source
Parlons-en dans le contexte de l'histoire de Java;
List
:La liste signifie qu'elle peut inclure n'importe quel objet. La liste était dans la version avant Java 5.0; Java 5.0 a introduit List, pour une compatibilité descendante.
List<?>
:?
signifie un objet inconnu pas un objet; l'?
introduction générique sert à résoudre le problème créé par Generic Type; voir les caractères génériques ; mais cela provoque également un autre problème:List< T> List< E>
Signifie une déclaration générique en supposant qu'aucun type T ou E dans votre projet Lib.
List< Object>
signifie paramétrage générique.la source
Dans votre troisième point, "T" ne peut pas être résolu car il n'est pas déclaré, généralement lorsque vous déclarez une classe générique, vous pouvez utiliser "T" comme nom du paramètre de type lié , de nombreux exemples en ligne, y compris
les didacticiels d'Oracle,utilisent "T" comme nom du paramètre type, par exemple, vous déclarez une classe comme:vous dites que la
FooHandler's
operateOnFoo
méthode attend une variable de type "T" qui est déclarée sur la déclaration de classe elle-même, avec cela à l'esprit, vous pouvez ajouter plus tard une autre méthode commedans tous les cas soit T, E ou U il y a tous les identifiants du paramètre de type, vous pouvez même avoir plus d'un paramètre de type qui utilise la syntaxe
dans votre quatrième point, bien qu'effectivement Sting soit un sous-type d'objet, dans les classes génériques il n'y a pas une telle relation, ce
List<String>
n'est pas un sous-type deList<Object>
ce sont deux types différents du point de vue du compilateur, cela est mieux expliqué dans cette entrée de blogla source
Théorie
String[]
peut être converti enObject[]
mais
List<String>
ne peut pas être converti enList<Object>
.Entraine toi
Pour les listes, c'est plus subtil que cela, car au moment de la compilation, le type d'un paramètre List transmis à une méthode n'est pas vérifié. La définition de la méthode pourrait aussi bien dire
List<?>
- du point de vue du compilateur, elle est équivalente. C'est pourquoi l'exemple # 2 de l'OP donne des erreurs d'exécution et non des erreurs de compilation.Si vous gérez
List<Object>
soigneusement un paramètre passé à une méthode afin de ne pas forcer une vérification de type sur aucun élément de la liste, vous pouvez définir votre méthode en utilisantList<Object>
mais en fait accepter unList<String>
paramètre du code appelant.A. Donc, ce code ne donnera pas d'erreurs de compilation ou d'exécution et fonctionnera réellement (et peut-être de manière surprenante?):
B. Ce code donnera une erreur d'exécution:
C. Ce code donnera une erreur d'exécution (
java.lang.ArrayStoreException: java.util.Collections$UnmodifiableRandomAccessList Object[]
):En B, le paramètre
set
n'est pas typéList
au moment de la compilation: le compilateur le voit commeList<?>
. Il y a une erreur d'exécution car au moment de l'exécution,set
devient l'objet réel transmismain()
, et c'est unList<String>
. UnList<String>
ne peut pas être lancéList<Object>
.En C, le paramètre
set
nécessite unObject[]
. Il n'y a aucune erreur de compilation et aucune erreur d'exécution lorsqu'il est appelé avec unString[]
objet comme paramètre. C'est parce queString[]
jetteObject[]
. Mais l'objet réel reçu partest()
reste unString[]
, il n'a pas changé. Ainsi, l'params
objet devient également unString[]
. Et l'élément 0 d'unString[]
ne peut pas être affecté à unLong
!(J'espère que j'ai tout ici, si mon raisonnement est erroné, je suis sûr que la communauté me le dira. MISE À JOUR: J'ai mis à jour le code de l'exemple A afin qu'il compile réellement, tout en montrant le point soulevé.)
la source
List<Object> cannot be applied to List<String>
. Vous ne pouvez pas passerArrayList<String>
à une méthode qui attendArrayList<Object>
.Le problème 2 est OK, car "System.out.println (set);" signifie "System.out.println (set.toString ());" set est une instance de List, donc complier appellera List.toString ();
Problème 3: ces symboles sont identiques, mais vous pouvez leur donner des spécifications différentes. Par exemple:
Problème 4: la collecte n'autorise pas la covariance des paramètres de type. Mais le tableau permet la covariance.
la source
Vous avez raison: String est un sous-ensemble d'Object. Puisque String est plus "précis" qu'Object, vous devez le convertir pour l'utiliser comme argument pour System.out.println ().
la source