La différence entre la Liste, List<?>, List<T>, une Liste<E>, et une Liste<Object>
Quelles sont les différences entre List
, List<?>
, List<T>
, List<E>
, et List<Object>
?
Maintenant, je n'ai pas aveuglément poser cette question, donc merci de ne pas fermer ce fil. Permettez-moi d'abord introduire le code de base:
private static List<String> names = new ArrayList<String>();
static {
names.add("Tom");
names.add("Peter");
names.add("Michael");
names.add("Johnson");
names.add("Vlissides");
}
public static void test(List<String> set){
System.out.println(set);
}
public static void main(String args[]){
test(names);
}
Je comprends que:
1.List
: est une crue de type, donc pas typesafe
. Il ne fera que générer une erreur d'exécution lors de la coulée est mauvais. Nous voulons une erreur de compilation quand le plâtre est mauvais. Recommandé de ne pas utiliser.
2.List<?>
: est une surabondance de génériques. Mais vous ne savez pas ce que c'est pour? Donc si je change le test
méthode pour
public static void test(List<?> set){
System.out.println(set);
}
il fonctionne toujours bien. Si vous pouvez expliquer l'utilisation de cette application, je vous en serais très reconnaissante.
MODIFIER: Si je fais ceci:
public static void test(List<?> set){
set.add(new Long(2)); //--> Error
set.add("2"); //--> Error
System.out.println(set);
}
mais si je change test
à ceci:
public static void test(List<String> set){
set.add(new Long(2)); //--> Error
set.add("2"); //--> Work
System.out.println(set);
}
3.List<T>
:
public static void test(List<T> set){ //T cannot be resolved
System.out.println(set);
}
Je suppose que je ne comprends pas cette syntaxe. J'ai vu quelque chose comme ça, et ça fonctionne:
public <T> T[] toArray(T[] a){
return a;
}
Veuillez l'expliquer moi s'il vous plaît? Parfois, je vois <T>
, ou <E>
, ou <U>
, <T,E>
. Sont-ils tous les mêmes ou qu'elles ne représentent quelque chose de différent?
4.List<Object>
public static void test(List<Object> set){
System.out.println(set);
}
Puis j'ai eu l'erreur The method test(List<Object>) is not application for the argument List<String>
pour le code ci-dessous. Je suis confus. J'ai pensé String
est un sous-ensemble de Object
?
public static void main(String args[]){
test(names);
}
EDIT: Si j'essaie ce
test((List<Object>)names);
puis j'ai eu Cannot cast from List<String> to List<Object>
- Aucune infraction, mais je pense que vous avez besoin de passer du temps à apprendre sur les médicaments génériques en Java.
- Ne vous en faites pas
- si vous pouvez consulter un livre ou de ressources en ligne que vous avez lu et que vous ne comprenez pas l'explication, il y a environ vos points, alors je voudrais répondre à votre question. Demander quel est le differenc entre la Liste<T> Liste<E> est la même chose que se demander quelle est la différence entre
int a;
etint b;
- J'ai vraiment envie d'apprendre, et je ne veux pas débattre avec vous sur si ma question est large ou pas? Donc, je suis désolé que je pose cette question trop vaste question, et en quelque sorte de vous ennuyer beaucoup. Toutefois, si vous insistez sur elle. Alors je suis de lecture Efficace Java par Joshua Bloch, sur le point
23
,24
. Même si, c'est un grand livre, l'explication est un peu dur pour moi de comprendre. Et quand j'essaie d'écrire des codes pour confirmer mon comprendre, je ne comprends pas les questions ci-dessus. Encore une fois, mes présenté des excuses. - Efficace Java suppose que vous connaissez les notions de base sur les génériques. Bon endroit pour commencer est: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html, Java Génériques et Collections formulaire de nick naftalin, ou si vous aimez la bonne combinaison de l'approche théorique et pratique, de lire Le Langage de Programmation Java 3e éd
- De Cirkel, angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html le lien est en bas.
- s'il vous plaît ne pas le nom de
List
commeset
🙁
Vous devez vous connecter pour publier un commentaire.
1) Corriger
2) Vous pouvez penser que l'on en "lecture seule" de la liste, où vous n'avez pas de soins sur le type des éléments.Pourraient par exemple être utilisés par une méthode qui retourne la longueur de la liste.
3) T, E et U sont les mêmes, mais les gens ont tendance à utiliser, par exemple, T pour type, E pour l'Élément, V pour la valeur et K de clé. La méthode qui compile dit qu'il a fallu un tableau d'un certain type, et retourne un tableau du même type.
4) Vous ne pouvez pas mélanger les oranges et les pommes. Vous serez en mesure d'ajouter un Objet à votre liste de chaînes, si vous pouvez passer une liste de chaînes à une méthode qui attend des listes d'objets. (Et pas tous les objets sont des chaînes de caractères)
2
. J'écris des codes de le démontrer dans2
. tyvmList<Object>
pour?<T> T[] toArray(T[] a) (method in List interface)
etE
est l'élément comme danspublic interface List<E> extends Collection<E>
. SiK
etV
semblent également commeE
pour moiPour la dernière partie:
Bien que le String est un sous-ensemble de l'Objet, mais List<String> n'est pas hérité de la Liste<Object>.
List<Object>
pour?La notation
List<?>
signifie "une liste de quelque chose (mais je ne dis pas que)". Depuis le code danstest
fonctionne pour n'importe quel type d'objet dans la liste, cela fonctionne comme une méthode formelle paramètre.À l'aide d'un paramètre de type (comme dans votre point 3), il faut que le paramètre du type d'être déclarée. La syntaxe Java pour qui est de mettre
<T>
devant de la fonction. C'est exactement analogue à la déclaration officielle des noms de paramètre à une méthode avant d'utiliser les noms dans le corps de la méthode.Concernant
List<Object>
ne pas accepter uneList<String>
, qui fait sens, car unString
n'est pasObject
; c'est une sous-classe deObject
. La solution est de déclarerpublic static void test(List<? extends Object> set) ...
. Mais alors leextends Object
est redondante, car chaque classe, directement ou indirectement, s'étendObject
.List<Object>
pour?List<?>
étant donné que la liste est assez spécifique, mais de type inconnu.List<Object>
serait vraiment "une liste de tout", car il peut en effet contenir quoi que ce soit.La raison pour laquelle vous ne pouvez lancer
List<String>
àList<Object>
est qu'il vous permettra de violer les contraintes de laList<String>
.Penser à le scénario suivant: Si j'ai un
List<String>
, elle est censée ne contenir que des objets de typeString
. (Qui est unfinal
classe)Si je peux l'appliquer à un
List<Object>
, puis qui me permet d'ajouterObject
à cette liste, violant ainsi le contrat initial deList<String>
.Donc, en général, si la classe
C
hérite de la classeP
, on ne peut pas dire queGenericType<C>
hérite également deGenericType<P>
.N. B. j'ai déjà commenté sur ce dans une réponse précédente, mais a voulu étendre sur elle.
List<Object>
?List<Object>
que ce genre de défaites le but de génériques. Cependant, il y a des cas où l'ancien code peut avoir unList
accepter différents types, de sorte que vous pourriez vouloir rénover le code à utiliser le type de paramétrage, simplement pour éviter les avertissements du compilateur pour les matières premières, les types. (Mais la fonctionnalité reste la même)Je vous conseille la lecture de Java casse-têtes. Il explique l'héritage, les génériques, les abstractions et des caractères génériques dans les déclarations assez bien.
http://www.javapuzzlers.com/
Dans votre troisième point, "T" ne peut pas être résolu en raison de sa non-déclaré, habituellement, lorsque vous déclarez une classe générique, vous pouvez utiliser le bouton "T" comme le nom de la lié paramètre de type, en ligne de nombreux exemples, y compris
oracle tutorielsutilisation de "T", comme le nom du paramètre de type, disons par exemple, vous déclarez une classe comme:vous dites que
FooHandler's
operateOnFoo
méthode attend une variable de type "T", qui est déclarée sur la déclaration de la classe elle-même, avec cela à l'esprit, vous pouvez les ajouter plus tard une autre méthode commedans tous les cas, soit T, E ou U il y a tous les éléments d'identification du paramètre de type, vous pouvez même avoir plus d'un type de paramètre qui utilise la syntaxe
dans votre suite ponint bien que efectively Sting est un sous-type de l'Objet, dans les génériques des classes il n'y a pas de telle relation,
List<String>
n'est pas un sous-type deList<Object>
ils sont deux différents types de le compilateur point de vue, cela est mieux expliqué dans cette entrée de blogLaissez-nous parler d'eux dans le contexte de Java de l'histoire ;
List
:Liste signifie qu'il peut inclure n'importe quel Objet. La liste a été la libération avant de Java 5.0; Java 5.0 a introduit Liste, pour des raisons de compatibilité descendante.
List<?>
:?
signifie Objet inconnu pas de tout Objet; le générique?
introduction pour résoudre le problème construite par Type Générique; voir les caractères génériques;mais cela entraîne également un autre problème:
List< T> List< E>
Signifie générique Déclaration à la prémisse de aucun T ou E type de votre projet, Lib.
List< Object>
moyen générique de paramétrage.Problème 2 est OK, parce que " le Système de.out.println(set);" signifie "le Système de.out.println(jeu.toString());" set est un exemple de Liste, de sorte complier Liste.toString();
Problème 3: ces symboles sont les mêmes, mais vous pouvez leur donner differet spécification. Par exemple:
Problème 4: la Collection ne permet pas de paramètre de type de covariance. Mais le tableau ne permettent de covariance.
Théorie
String[]
peut être coulé àObject[]
mais
List<String>
ne peut pas être lancé àList<Object>
.Pratique
Pour les listes, il est plus subtil que ça, car à moment de la compilation le type d'une Liste de paramètres passés à une méthode n'est pas cochée. La définition de la méthode pourrait tout aussi bien dire
List<?>
- du compilateur, du point de vue, c'est équivalent. C'est pourquoi l'OP de l'exemple n ° 2 donne des erreurs d'exécution, pas d'erreurs de compilation.Si vous manipulez un
List<Object>
paramètre passé à une méthode avec soin afin de ne pas forcer une vérification du type sur n'importe quel élément de la liste, vous pouvez avoir votre méthode définie à l'aide deList<Object>
mais en fait accepter unList<String>
paramètre dans le code appelant.A. Si ce code ne sera pas donner de la compilation ou de l'exécution des erreurs et sera effectivement (et peut-être étonnamment?) travail:
B. Ce code vous donnera une erreur d'exécution:
C. Ce code vous 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 ne voit en elle qu'List<?>
. Il y a une erreur d'exécution, car au moment de l'exécution,set
devient l'objet même passé demain()
, et c'est unList<String>
. UnList<String>
ne peut pas être lancé àList<Object>
.En C, le paramètre
set
implique unObject[]
. Il n'y a pas d'erreur de compilation, et aucune erreur d'exécution lorsqu'elle est appelée avec unString[]
objet en tant que paramètre. C'est parce queString[]
jette àObject[]
. Mais l'objet réel reçu partest()
reste unString[]
, il n'a pas changé. Ainsi, leparams
objet devient aussi unString[]
. Et l'élément 0 de unString[]
ne peut pas être attribué à unLong
!(J'espère que j'ai tout ici, si mon raisonnement est faux, je suis sûr que la communauté va me dire.)
List<Object> cannot be applied to List<String>
. Vous vous ne pouvez pas passArrayList<String>
à une méthode qui attendArrayList<Object>
.Vous avez raison: String est un sous-ensemble de l'Objet. Depuis que la Chaîne est plus "précis" de l'Objet, vous devez le jeter à l'utiliser comme un argument pour le Système.out.println().