89 votes

Java: borné, ou de caractères spéciaux délimitée type de paramètre?

Récemment, j'ai lu cet article: http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html

Ma question est, au lieu de créer une méthode comme ceci:

public void drawAll(List<? extends Shape> shapes){
    for (Shape s: shapes) {
        s.draw(this);
    }
}

Je peux créer une méthode comme ceci, et il fonctionne très bien:

public <T extends Shape> void drawAll(List<T> shapes){
    for (Shape s: shapes) {
        s.draw(this);
    }
}

de quelle manière dois-je utiliser? Est générique utile dans ce cas?

Merci beaucoup

140voto

polygenelubricants Points 136838

Cela dépend de ce que vous devez faire. Vous devez utiliser le délimitée type de paramètre que si vous vouliez faire quelque chose comme ceci:

public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
    if (shape.isPretty()) {
       shapes.add(shape);
    }
}

Ici, nous avons un List<T> shapes et T shape, donc nous pouvons en toute sécurité shapes.add(shape). Si elle a été déclarée List<? extends Shape>, vous pouvez ne PAS en toute sécurité add pour elle (parce que vous pouvez avoir un List<Square> et Circle).

Donc, en donnant un nom à un délimitée paramètre de type, nous avons la possibilité de les utiliser ailleurs dans notre méthode générique. Cette information n'est pas toujours nécessaire, bien sûr, donc si vous n'avez pas besoin d'en savoir beaucoup sur le type (par exemple, votre drawAll), puis il suffit de joker, c'est suffisant.

Même si vous n'êtes pas en se référant à la délimitée paramètre de type nouveau, un délimitée paramètre de type est toujours nécessaire si vous disposez de plusieurs limites. Voici une citation de Angelika Langer Java Génériques Faq

Quelle est la différence entre un générique lié et un paramètre de type lié?

Un joker peut avoir qu'une seule tenue, alors qu'un paramètre de type peut avoir plusieurs limites. Un joker peut avoir une baisse de régime ou une limite supérieure, alors qu'il n'y a pas une telle chose comme une limite inférieure pour un paramètre de type.

Générique de limites et d'un paramètre de type de limites sont souvent confondus, car ils sont tous deux appelés limites et ont en partie similaire à la syntaxe. [...]

Syntaxe:

  type parameter bound     T extends Class & Interface1 & … & InterfaceN

  wildcard bound  
      upper bound          ? extends SuperType
      lower bound          ? super   SubType

Un joker peut avoir qu'un seul tenu, soit une baisse ou une limite supérieure. Une liste des génériques de limites n'est pas autorisée.

Un paramètre de type, en contraste, peut avoir plusieurs limites, mais il n'y a pas une telle chose comme une limite inférieure pour un paramètre de type.

Citations de Efficace Java 2nd Edition, Point 28: Utilisation délimitée des caractères génériques pour augmenter l'API de flexibilité:

Pour une flexibilité maximale, utilisez les caractères génériques types des paramètres d'entrée qui représentent les producteurs ou les consommateurs. [...] PECS stands pour le producteur-extends, de la consommation-super [...]

Ne pas utiliser de caractères génériques types de types de retour. Plutôt que de fournir une plus grande flexibilité pour vos utilisateurs, il serait forcer à utiliser des types génériques dans le code client. Correctement utilisés, les types génériques sont presque invisible pour les utilisateurs d'une classe. Ils provoquent des méthodes pour accepter les paramètres qu'ils doivent accepter et de rejeter ceux qu'ils devraient rejeter. Si l'utilisateur de la classe a à réfléchir sur les types génériques, il y a probablement quelque chose de mal avec la classe de l'API.

En appliquant les PECS principe, nous pouvons maintenant revenir à notre addIfPretty exemple et de le rendre plus souple par écrit les éléments suivants:

public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }

Maintenant, nous pouvons addIfPretty, disons, un Circle, pour un List<Object>. C'est évidemment typesafe, et pourtant notre déclaration d'origine n'était pas assez souple.

Questions connexes


Résumé

  • N'utilisez délimitée paramètres de type et les jokers, ils augmentent la flexibilité de votre API
  • Si le type nécessite plusieurs paramètres, vous n'avez pas d'autre choix que d'utiliser délimitée paramètre de type
  • si le type nécessite une limite inférieure, vous n'avez pas d'autre choix que d'utiliser délimitée générique
  • "Producteurs" ont upperbounds, "consommateurs" qui ont lowerbounds
  • Ne pas utiliser de caractères génériques dans les types de retour

6voto

Dans votre exemple, vous n'avez pas vraiment besoin d'utiliser T, puisque vous ne faites pas usage de ce type de n'importe où ailleurs.

Mais si vous avez quelque chose comme:

public <T extends Shape> T drawFirstAndReturnIt(List<T> shapes){
    T s = shapes.get(0);
    s.draw(this);
    return s;
}

ou comme polygenlubricants dit, si vous voulez faire correspondre le type de paramètre dans la liste avec un autre type de paramètre:

public <T extends Shape> void mergeThenDraw(List<T> shapes1, List<T> shapes2) {
    List<T> mergedList = new ArrayList<T>();
    mergedList.addAll(shapes1);
    mergedList.addAll(shapes2);
    for (Shape s: mergedList) {
        s.draw(this);
    }
}

Dans le premier exemple, vous obtenez un peu plus de type de sécurité, puis retour de la Forme, puisque vous pouvez ensuite passer le résultat d'une fonction qui peut prendre un enfant de Forme. Par exemple, vous pouvez passer un List<Square> ma méthode, puis passer l'résultant Place à une méthode qui ne prend que des Carrés. Si vous avez utilisé le '?' vous devez lancer la Forme obtenue à Carré qui ne serait pas le type de coffre-fort.

Dans le deuxième exemple vous assurer que les deux listes ont le même type de paramètre (qui vous ne pouvez pas faire avec"?", car chaque"? " est différent), de sorte que vous pouvez créer une liste qui contient tous les éléments des deux à la fois.

0voto

Nikita Rybak Points 36641

La deuxième manière est un peu plus verbeux, mais il vous permet de vous rapporter T à l'intérieur:

for (T shape : shapes) {
    ...
}

C'est la seule différence, comme je le comprends.

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