86 votes

Pourquoi ne pouvez-vous pas avoir plusieurs interfaces dans un délimitée générique générique?

Je sais qu'il y a toutes sortes de contre-intuitive, les propriétés de Java les types génériques. Voici l'un en particulier que je ne comprends pas, et qui, je l'espère, quelqu'un peut m'expliquer. Lors de la spécification d'un paramètre de type pour une classe ou une interface, vous pouvez liés de sorte qu'il doit implémenter plusieurs interfaces avec d' public class Foo<T extends InterfaceA & InterfaceB>. Toutefois, si vous êtes l'instanciation d'un objet réel, cela ne fonctionne pas plus. List<? extends InterfaceA> est bien, mais List<? extends InterfaceA & InterfaceB> ne parvient pas à compiler. Considérez les points suivants complet extrait:

import java.util.List;

public class Test {

  static interface A {
    public int getSomething();
  }

  static interface B {
    public int getSomethingElse();
  }

  static class AandB implements A, B {
    public int getSomething() { return 1; }
    public int getSomethingElse() { return 2; }
  }

  // Notice the multiple bounds here. This works.
  static class AandBList<T extends A & B> {
    List<T> list;

    public List<T> getList() { return list; }
  }

  public static void main(String [] args) {
    AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!
    foo.getList().add(new AandB());
    List<? extends A> bar = new LinkedList<AandB>(); // This is fine too
    // This last one fails to compile!
    List<? extends A & B> foobar = new LinkedList<AandB>();
  }
}

Il semble que la sémantique de l' bar devraient être bien définies, je ne peux pas penser de la perte de tout type de sécurité en permettant à une intersection de deux types, plutôt qu'un seul. Je suis sûr qu'il ya une explication. Personne ne sait ce que c'est?

45voto

irreputable Points 25577

Fait intéressant, l'interface java.lang.reflect.WildcardType dirait qu'il prend en charge à la fois les limites supérieures limites inférieures et pour un générique arg; et chacun d'eux peut contenir plusieurs limites

Type[] getUpperBounds();
Type[] getLowerBounds();

C'est la façon dont delà de ce que le langage permet de. Il y a une face cachée de commentaire dans le code source

// one or many? Up to language spec; currently only one, but this API
// allows for generalization.

L'auteur de l'interface semble considérer que c'est un accident de limitation.

Les conserves de réponse à votre question est, les génériques est déjà trop compliqué comme il est; ajouter plus de complexité qui pourrait s'avérer être la dernière paille.

Pour permettre à un joker pour avoir plusieurs limites supérieures, on doit numériser à travers la spécification et assurez-vous que l'ensemble du système fonctionne toujours.

De la peine je sais que serait dans l'inférence de type. Le courant de règles d'inférence ne peut tout simplement pas faire face avec l'interception types. Il n'y a pas de règle pour réduire une contrainte A&B << C. Si nous l'avons réduit à

    A<<C 
  or
    A<<B

courant moteur d'inférence doit passer par une révision majeure de permettre une telle bifurcation. Mais le vrai problème est, ce qui permet de multiples solutions, mais il n'y a aucune raison de préférer l'une sur l'autre.

Cependant, l'inférence n'est pas indispensable à la sécurité de type; on peut simplement refuser d'en déduire dans ce cas, et de demander au programmeur de remplir de façon explicite dans le type des arguments. Par conséquent, la difficulté de l'inférence n'est pas un argument fort contre l'interception types.

28voto

emboss Points 20708

De la Java Language Specification:

4.9 Intersection Types Une intersection type prend la forme T1 & ... & Tn, n>0, où Ti, 1en, sont des expressions de type. Intersection types surviennent dans le processus de capture et de conversion (§5.1.10) et l'inférence de type (§15.12.2.7). Il n'est pas possible d'écrire une intersection type directement dans le cadre d'un programme; aucune syntaxe prend en charge cette. Les valeurs d'un carrefour de type sont ces objets que sont les valeurs de tous les types de Ti, pour 1dans.

Alors pourquoi ce n'est pas pris en charge? Ma conjecture est, que devez-vous faire d'une telle chose? - supposons que c'était possible:

List<? extends A & B> list = ...

Alors ce qui doit

list.get(0);

de retour? Il n'y a pas de syntaxe pour capturer une valeur de retour d' A & B. L'ajout de quelque chose dans une telle liste ne serait pas possible non plus, donc, c'est essentiellement inutile.

13voto

Bohemian Points 134107

Pas de problème... il suffit de déclarer le type dont vous avez besoin dans la signature de la méthode.

Cette compile:

public static <T extends A & B> void main(String[] args) throws Exception
{
    AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!
    foo.getList().add(new AandB());
    List<? extends A> bar = new LinkedList<AandB>(); // This is fine too
    List<T> foobar = new LinkedList<T>(); // This compiles!
}

2voto

edutesoy Points 3024

Bonne question. Il m'a fallu un certain temps à comprendre.

Vous permet de simplifier votre cas: Vous êtes à essayer de faire la même chose que si vous déclarez une classe qui étend la classe 2 interfaces, et ensuite une variable a un type de ces 2 interfaces, quelque chose comme ceci:

  class MyClass implements Int1, Int2 { }

  Int1 & Int2 variable = new MyClass()

Bien sûr, illégal. Et c'est l'équivalent de ce que vous essayez de faire avec les génériques. Ce que vous essayez de faire est:

  List<? extends A & B> foobar;

Mais, ensuite, d'utiliser foobar, vous devez utiliser une variable de deux interfaces de cette façon:

  A & B element = foobar.get(0);

Ce qui est pas légal en Java. Cela signifie, que vous déclarez les éléments de la liste comme étant de 2 types en même temps, et même si notre cerveau peut traiter avec elle, le langage Java ne peut pas.

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