57 votes

Pourquoi ne puis-je pas utiliser un argument de type dans un paramètre de type à plusieurs bornes?

Donc, je comprends que le suivant ne fonctionne pas, mais pourquoi ne pas travailler?

Adaptateur d'interface<E> {}

classe Adaptulator<I> {
 <E, s'étend Un je & Carte<E>> void ajouter(Classe<E> extl, Classe<A> intl) {
 addAdapterFactory(nouveau AdapterFactory<E, A>(extl, intl));
}
}

L' add() méthode me donne une erreur de compilation, "Ne peut pas spécifier supplémentaire lié à la Carte<E> lorsque le premier est lié à un paramètre de type" (dans Eclipse), ou "Type de paramètre ne peut pas être suivie par d'autres limites" (dans l'IDÉE), faites votre choix.

Il est clair que vous n'êtes Pas Autorisé à utiliser le paramètre de type I il y, avant la &, et c'est tout. (Et avant de vous demander, il ne fonctionne pas si vous passez 'em, car il n'y a aucune garantie que l' I n'est pas une classe concrète.) Mais pourquoi pas? J'ai regardé par Angelika Langer de la FAQ de et ne pouvez pas trouver une réponse.

Généralement, lorsque certains génériques de prescription semble arbitraire, c'est parce que vous avez créé une situation où le type de système ne peut pas l'application effective de la décision correcte. Mais je ne vois pas ce cas serait de briser ce que j'essaie de faire ici. Je dirais peut-être qu'il a quelque chose à faire avec la méthode de répartition d'après le type d'effacement, mais il n'y a qu'un add() méthode, de sorte qu'il n'est pas comme si il n'y a aucune ambiguïté...

Quelqu'un peut-il démontrer le problème pour moi?

35voto

Bruno De Fraine Points 11478

Je suis également pas sûr de savoir pourquoi la restriction est là. Vous pourriez essayer d'envoyer un sympathique e-mail pour les concepteurs de Java 5 Génériques (principalement Gilad Bracha et Neal Gafter).

J'imagine qu'ils voulaient soutenir seulement un minimum absolu d' intersection types (qui est ce que plusieurs limites sont essentiellement), pour faire de la langue pas plus complexe que nécessaire. Une intersection ne peut pas être utilisé comme une annotation de type; un programmeur peut qu'exprimer une intersection lorsqu'il apparaît que la limite supérieure d'une variable de type.

Et pourquoi était-ce le cas même pris en charge? La réponse est que plusieurs bornes vous permettent de contrôler l'effacement, ce qui permet de maintenir la compatibilité binaire lorsque generifying de classes existantes. Comme expliqué dans l'article 17.4 de l' ouvrage par nick naftalin et Wadler, un max méthode devrait logiquement avoir la signature suivante:

public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll)

Toutefois, cela efface le:

public static Comparable max(Collection coll)

Ce qui ne correspond pas à la signature historique de l' max, et les causes de vieux clients de se briser. Avec plusieurs limites, seule la plus à gauche est considéré comme lié pour l'effacement, donc si max est donné la signature suivante:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

Puis l'effacement de sa signature devient:

public static Object max(Collection coll)

Qui est égal à la signature d' max avant de Génériques.

Il semble plausible que le Java concepteurs seulement soucié ce cas simple et restreinte d'autres (plus avancé) les utilisations d'intersection types parce qu'ils étaient tout simplement pas sûr de la complexité qu'il peut apporter. Donc, la raison de cette décision de conception n'a pas besoin d'être un possible problème de sécurité (comme le laisse entendre la question).

La discussion sur l'intersection des types et des restrictions de génériques dans un prochain OOPSLA papier.

16voto

Chris Povirk Points 1793

Deux raisons possibles pour interdire ce:

  1. La complexité. Soleil bug 4899305 suggère qu'un encadrement contenant un paramètre de type et d'autres types paramétrés permettrait encore plus compliqué mutuellement récursives types de existent déjà. En bref, la réponse de Bruno.

  2. La possibilité de spécifier des drogues illégales. Plus précisément, l'extension d'une interface générique, deux fois avec des paramètres différents. Je ne peux pas venir avec un non-exemple artificiel, mais:

    /** Contient un Comparateur<String> qui implémente également le type T. */
    classe StringComparatorHolder<T, C extends T & Comparateur de<Chaîne de caractères>> {
     privé de la finale C du comparateur;
     // ...
    }
    
    void foo(StringComparatorHolder<Comparateur<Integer>, ?> titulaire) { ... }

Maintenant, holder.comparator est Comparator<Integer> et Comparator<String>. Il n'est pas clair pour moi exactement comment beaucoup de peine ce qui en découleraient pour le compilateur, mais c'est clairement pas bon. Supposons en particulier que Comparator avaient une méthode comme ceci:

void sort(List<? extends T> liste);

Notre Comparator<Integer> / Comparator<String> hybride a maintenant deux méthodes avec le même effacement:

void sort(List<? s'étend Integer> liste);
void sort(List<? s'étend String> liste);

C'est pour ce genre de raisons que vous ne pouvez pas spécifier de ce type directement:

<T extends Comparateur<Integer> & Comparateur de<Chaîne de caractères>> void bar() { ... }
java.util.Comparateur ne peut pas être héritée avec des arguments différents:
 <java.lang.Integer> et <java.lang.String>

Depuis <A extends I & Adapter<E>> vous permet de faire la même chose indirectement, c'est, trop.

12voto

Jan Soltis Points 1733

Voici une autre citation de JLS :

La forme d'une borne est restreinte (seul le premier élément peut être une variable de classe ou de type, et une seule variable de type peut apparaître dans la borne) pour empêcher certaines situations gênantes d'exister .

Quelles sont exactement ces situations délicates, je ne sais pas.

2voto

Miserable Variable Points 17515

Cela n'a probablement pas de réponse à la racine de la question, mais je veux juste faire remarquer que la spec sans ambiguïté l'interdit. Recherche Google pour le message d'erreur qui m'a pris à cette entrée de blog, ce qui souligne encore davantage jls 4.4:

La limite correspond soit à une variable de type ou une classe ou une interface de type T, éventuellement suivie par d'autres types d'interface I1 , ..., En.

Donc, si vous utilisez le paramètre de type liée, vous ne pouvez pas utiliser n'importe quel autre lié, tout comme le message d'erreur dit.

Pourquoi la restriction? Je n'ai aucune idée.

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