Question

J'ai une interface pour une variété de classes, qui devraient tous mettre en œuvre Iterator, j'ai donc quelque chose comme

public interface A extends Iterable<A> { ...otherMethods()... }

Pour les classes concrètes, cependant, cela signifie que je dois utiliser

public class B implements A { public Iterator<A> iterator() {...} }

quand je préférerais (ou du moins, pense que je préfère) d'utiliser public Iterator<B> iterator() {...} de telle sorte que l'utilisation concrète de la classe pourrait avoir le type explicite (dans le cas où je voulais des méthodes qui ne sont pas dans l'interface soit disponible , ou une telle. Peut-être qui ne devrait jamais arriver? ou est mauvaise conception si elle fait?

Le revers est que l'utilisation de l'interface Iterator

public interface A extends Iterator<A> { ...otherMethods()... }

les classes concrètes compilent très bien avec

public class B implements A { public B next() {...} }

Ce qui donne?

Était-ce utile?

La solution

La classe de béton compile bien parce que B extends A, et depuis Java 5 un type de retour sur une sous-classe peut être une sous-classe du type de retour sur la superclasse.

En ce qui concerne le générique, je l'ai frappé le même mur, et vous avez deux options que je connais.

L'un est à paramaterize A:

 public interface A<T extends A> extends Iterable<T>

alors:

public class B implements A<B>

Cependant, cela a un inconvénient que vous devez donner un paramètre de A, au lieu de l'avoir fixé, même si vous voulez A:

private class NoOneSees implements A<A>

Quant à la question de savoir si vous voulez réellement Iterator<B>, dans le cas d'un Iterable, le plus probable est préférable, et considérant que ce sont des interfaces, la nécessité de redéclarer le paramètre est probablement raisonnable. Il est un peu plus compliqué si vous commencez héritant des classes concrètes, et pour des choses qui ont un sens autre qu'un Iterable, où vous voudrez peut-covariance. Par exemple:

public interface Blah<T> {
    void blah(T param);
}

public class Super implements Blah<Super> {
    public void blah(Super param) {}
}

public class Sub extends Super {
    public void blah(Super param) {}
   //Here you have to go with Super because Super is not paramaterized
   //to allow a Sub here and still be overriding the method.
}

De même pour covariance, vous ne pouvez pas déclarer en elle, une variable de type Iterator<A> puis attribuez-lui un Iterator<B> même si B extends A.

L'autre option est en direct avec le fait que la mise en œuvre plus / sous-classes se font toujours référence A.

Autres conseils

Carl avait raison, ma première réponse ne compile pas, mais cela semble. Je ne sais pas si c'est ce que vous voulez exactement.

public interface A<T extends A> extends Iterable<T> {

}

public class B implements A<B> {

    @Override
    public Iterator<B> iterator() {
        return null;
    }

Les autres réponses ont le sens droit - mais vous obtiendrez la mécanique à droite en déclarant le type générique comme

A<T extends A<T>>

Cela force une classe à retourner un itérateur qui est de son propre type ou moins - de sorte que vous seriez en mesure de déclarer

class B implements A<B>

mais pas

class B implements A<A>

que je pense est plus proche de ce que vous voulez (à savoir les mises en œuvre doivent revenir itérateurs sur eux-mêmes, plutôt que simplement sur As).

Notez que vos expériences avec Iterator vs tronc Iterable de l'absence de covariance des types génériques; une instance de B est un A, mais un Iterator<B> est pas un Iterator<A>.

Je suppose que cela est ce que vous voulez:

public interface A<T extends A<?>>  extends Iterable<T>

public class B implements A<B> {
  public Iterator<B> iterator() {...}
}

Vos décisions de conception sont vos propres, mais je ne peux pas penser à une raison pour chaque classe dans la conception à la mise en œuvre Iterable. Il doit y avoir une sorte de chose qui est contenu dans une collection, mais ne sont pas en fait une collection elle-même. Je prendrais un long regard dur à la conception fondamentale. Peut-être que certains iterables voudront revenir itérateurs des choses qui ne concernent pas eux-mêmes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top