73 votes

Génériques Java

Quelqu'un peut-il expliquer, aussi détaillé que possible, les différences entre les types suivants?

 List

List<Object>

List<?>
 

Puis-je obtenir une réponse, pas un lien?

Laissez-moi rendre cela plus spécifique.

Quand voudrais-je utiliser

 public void CanYouGiveMeAnAnswer( List l ){}
 

?

Quand voudrais-je utiliser

 public void CanYouGiveMeAnAnswer( List<Object> l ){}
 

?

Quand voudrais-je utiliser

 public void CanYouGiveMeAnAnswer( List<?> l ){}
 

?

106voto

jjohn Points 1518

Comme les messages d'autres l'ont noté, vous avez une question sur une fonctionnalité appelée génériques. En C++, cela s'appelle des modèles. La Java bestioles sont beaucoup plus docile à traiter.

Permettez-moi de répondre à vos questions fonctionnellement (si ce n'est pas un vilain mot pour OO discussions).

Avant de génériques, vous avez eu la bonne vieille classes concrètes comme Vecteur.

Vector V = new Vector();

Vecteurs de tenir tout objet ancien que vous leur donnez.

V.add("This is an element");
V.add(new Integer(2));
v.add(new Hashtable());

Cependant, ils le font en jetant tout ce que vous donner à un Objet (la racine de toutes les classes Java). C'est OK jusqu'à ce que vous essayez de récupérer les valeurs stockées dans le Vecteur. Lorsque vous le faites, vous avez besoin de convertir la valeur de retour dans la classe d'origine (si vous voulez faire quelque chose de significatif avec elle).

String s = (String) v.get(0);
Integer i = (Integer) v.get(1);
Hashtable h = (Hashtable) v.get(2);

Casting devient très vite ennuyant. De plus, le compilateur couine à vous sur décoché jette. Pour un exemple frappant de cela, utiliser le XML-RPC bibliothèque d'Apache (version 2 de toute façon). Le problème le plus important est que les consommateurs de votre Vecteur d'avoir à connaître précisément la classe de ses valeurs au moment de la compilation, pour exprimer correctement. Dans les cas où le producteur du Vecteur et de la consommation sont complètement isolés les uns des autres, ce peut être une issue fatale.

Entrée des génériques. Les génériques de tenter de créer des classes fortement typées pour générique opérations.

ArrayList<String> aList = new ArrayList<String>();
aList.add("One");
String element = aList.get(0); // no cast needed
System.out.println("Got one: " + element); 

Maintenant, si vous jetez un oeil à la tristement célèbre gang de quatre Modèles de Conception de livre, vous verrez qu'il y a une certaine sagesse dans le divorce des variables à partir de leur mise en œuvre en classe. Il est préférable de penser à des contrats plutôt que la mise en œuvre. Donc, on pourrait dire que tous les objets de la Liste faire les mêmes choses: add(), get(), size(), etc. Cependant, il existe de nombreuses implémentations de la Liste des opérations susceptibles de choisir d'obéir au contrat de diverses manières (par exemple, ArrayList). Cependant, le type de données de ces objets est à gauche que l'exécution de la considération pour vous, l'utilisateur de la classe générique. Mettez tout cela ensemble et vous verrez la ligne suivante de code très souvent:

List<String> L = new ArrayList<String>();

Vous devriez lire que "L est une sorte de Liste qui traite les objets String". Lorsque vous commencez à traiter avec les classes de Fabrique, il est essentiel de traiter avec des contrats plutôt que des implémentations spécifiques. Les usines produisent des objets de différents types à l'exécution.

L'utilisation de génériques est assez facile (la plupart du temps). Cependant, un jour terrible, vous pouvez décider vous souhaitez mettre en place une classe générique. Peut-être que vous avez pensé à une nouvelle Liste mise en œuvre. Lorsque vous définissez cette catégorie, vous utilisez <t> comme un espace réservé pour le genre d'objet qui sera manipulé par les méthodes. Si vous êtes confus, utilisez les classes génériques pour la Liste jusqu'à ce que vous sentez à l'aise. Ensuite, vous pouvez plonger dans la mise en œuvre avec un peu plus de confiance. Ou vous pouvez regarder le code source pour les divers Liste des classes qui sont fournies avec le JRE. L'Open source est grande de cette façon.

Jetez un oeil à l'Oracle/Sun docs sur les génériques. Des acclamations.

42voto

OscarRyz Points 82553

Dans mes propres termes simples:

Liste

Déclarer un ordinaire de la collection, peut contenir n'importe quel type, et sera toujours l'Objet de retour.

List<Object>

Créer une liste qui peut contenir n'importe quel type d'objet, mais ne peut affectées à une autre Liste de<Object>

Par exemple, cela ne fonctionne pas;

List<Object> l = new ArrayList<String>();

Bien sûr, vous pouvez ajouter quoi que ce soit, mais seulement peut tirer de l'Objet.

List<Object> l = new ArrayList<Object>();

l.add( new Employee() );
l.add( new String() );

Object o = l.get( 0 );
Object o2 = l.get( 1 );

Enfin

List<?>

Vous permettra d'assigner n'importe quel type, y compris

List <?> l = new ArrayList(); 
List <?> l2 = new ArrayList<String>();

Ce serait appelé la collecte de l' inconnu et depuis le dénominateur commun de l' inconnu est l'Objet, vous serez en mesure d'aller chercher des Objets ( une coïncidence )

L'importance de l' inconnu vient quand il est utilisé avec sous-classement:

List<? extends Collection> l = new ArrayList<TreeSet>(); // compiles

List<? extends Collection> l = new ArrayList<String>(); // doesn't,
// because String is not part of *Collection* inheritance tree.

J'espère que l'utilisation de Collection que le type ne crée pas de confusion, c'est le seul arbre qui est venu à mon esprit.

La différence ici est que l est une collection de unknow qui appartient à la Collection de la hiérarchie.

16voto

Eric Lindauer Points 664

Pour ajouter à la déjà de bonnes réponses ici:

Des arguments de méthode:

List<? extends Foo>

bon choix si vous n'avez pas l'intention de modifier la liste, et seulement attention à ce que tout dans la liste est programmable de type 'Foo'. De cette façon, le visiteur peut passer d'une Liste<FooSubclass> et votre méthode fonctionne. Généralement le meilleur choix.

List<Foo>

bon choix si vous avez l'intention d'ajouter des Foo objets de la liste dans votre méthode. L'appelant ne peut pas passer dans une Liste<FooSubclass>, que vous avez l'intention d'ajouter un truc pour la Liste.

List<? super Foo>

bon choix si vous avez l'intention d'ajouter des Foo objets de la liste, et ce n'est pas important ce que le reste est dans la liste (c'est à dire, vous êtes ok obtention d'une Liste de<Object> qui contient un "Chien" qui n'a rien à voir avec les Foo).

Valeurs de retour des méthodes

tout comme arguments de méthode, mais avec les avantages inversée.

List<? extends Foo>

Garantit que tout dans la Liste retournée est de type 'Foo'. Il pourrait être la Liste<FooSubclass> si. L'appelant ne peut pas ajouter à la Liste. C'est votre go-to choix et le cas le plus fréquent, et de loin.

List<Foo>

Tout comme la Liste des<? s'étend Foo>, mais aussi permet à l'appelant d'ajouter à la Liste. Moins commun.

List<? super Foo>

permet à l'appelant d'ajouter Foo objets de la Liste, mais ne pouvons garantir ce sera retourné à partir de la liste.get(0)... il pourrait être quelque chose de Toto à l'Objet. La seule garantie est que ce ne sera pas une liste de "Chien" ou d'autres choix qui empêcherait la liste.ajouter(foo) d'être juridique. De très rares cas d'utilisation.

J'espère que ça aide. Bonne chance!

ps. Pour résumer... deux questions...

avez-vous besoin d'ajouter à la Liste? Ne vous vous souciez de ce qui est dans la liste?

oui oui - utilisation de la Liste<Foo>.

oui non - utilisation de la Liste<? super Toto>.

non oui - utiliser <? s'étend Foo> --- la plupart des communes.

ne pas utiliser <?>.

15voto

Rob Points 31432

Je vous renvoie à l'excellent tutoriel Java Generics et au tutoriel "avancé" Generics , tous deux disponibles auprès de Sun Microsystems. Le livre Java Generics and Collections constitue une autre ressource précieuse .

4voto

John Gardner Points 10882

Explication la plus simple qui n'est pas "RTFM":

List

Va générer beaucoup d'avertissements du compilateur, mais est essentiellement équivalent à:

List<Object>

Alors que:

List<?>

fondamentalement signifie que ses quelque chose de générique, mais vous ne savez pas ce que le type générique est. Son grand pour se débarrasser des avertissements du compilateur lorsque vous ne peut pas modifier les types de retour d'autres choses que juste de rentrer de la Liste. Elle est beaucoup plus utile dans le formulaire:

List<? extends SomeOtherThing>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X