web-dev-qa-db-fra.com

Qui étend les interfaces? Et pourquoi?

AFAIK, ma classe extends classes parentes et implements interfaces. Mais je rencontre une situation où je ne peux pas utiliser implements SomeInterface. C'est la déclaration d'un type générique. Par exemple:

public interface CallsForGrow {...}

public class GrowingArrayList <T implements CallsForGrow>  // BAD, won't work!
                              extends ArrayList<T> 

Ici, l'utilisation de implements est syntaxiquement interdite. J'ai d'abord pensé qu'il était interdit d'utiliser l'interface à l'intérieur de <>, mais non. C'est possible, je n'ai qu'à utiliser extends au lieu de implements. En conséquence, je "prolonge" une interface. Cet autre exemple fonctionne:

public interface CallsForGrow {...}

public class GrowingArrayList <T extends CallsForGrow>  // this works!
                              extends ArrayList<T> 

Cela me semble être une incohérence syntaxique. Mais peut-être que je ne comprends pas certaines finesses de Java 6? Y a-t-il d'autres endroits où je devrais étendre les interfaces? L'interface, que je veux étendre, devrait-elle avoir des fonctionnalités spéciales?

20
Gangnus

Dans le cas des variables de type génériques, le compilateur ne se soucie pas réellement si T est une classe, une interface, une énumération ou une annotation. Tout ce qui compte c'est qu'il s'agit d'un type avec un ensemble donné de sous-et super-types.

Et il n'y a aucune raison de compliquer la syntaxe simplement parce qu'à un autre endroit (où vous implémentez réellement une interface) la distinction entre les classes et les interfaces est pertinente (par exemple si vous implement une interface, vous devez implémenter tous méthodes qu'il définit, mais vous n'en avez pas besoin si vous extend une classe (non abstraite)).

En supposant un instant que vous deviez écrire implements ici, vous auriez également besoin d'une syntaxe distincte pour les valeurs de enum (au lieu d'écrire simplement <E extends Enum<E>>) et des annotations (que vous pouvez facilement déclarer en utilisant <A extends Annotation>).

Le seul endroit où vous avez besoin d'écrire implements est au point où vous implémentez réellement l'interface. À ce point (et ce point uniquement) la différence est importante, car vous devez implémenter les méthodes définies dans l'interface. Pour tout le monde, peu importe si un A donné est une classe de base ou une interface implémentée de B: c'est un super-type et c'est tout ce qui compte.

Notez également qu'il existe un autre endroit où vous utilisez extends avec des interfaces:

interface A {
}

interface B extends A {
}

À ce stade, implements serait faux, car B n'implémente pas A.

25
Joachim Sauer

Lorsque Java 5, et en particulier les génériques, a été initialement mis à la disposition des développeurs qui avaient manifesté un intérêt, la syntaxe était tout à fait différente. Au lieu de Set<? extends Foo> et Set<? super Bar> cela a Set<+Foo> et Set<-Foo>. Cependant, les commentaires étaient qu'il n'était pas clair si + signifiait plus spécifique ou plus large (plus de classes). Sun a répondu à ces commentaires en modifiant la syntaxe, mais dans la contrainte de ne pas introduire de nouveaux mots clés, ce qui aurait posé un problème de compatibilité descendante.

Le résultat est que ni l'un ni l'autre n'est tout à fait naturel. Comme vous le constatez, extends est surchargé pour parler de classes "étendant" les interfaces, ce qui n'est pas le langage utilisé dans d'autres contextes; et super est surchargé pour signifier "est une superclasse de", qui est la direction opposée de la relation précédemment exprimée par le mot-clé, c'est-à-dire se référant à une superclasse.

Cependant, les principes fondamentaux de ce qu'est une interface ne sont pas affectés par ce changement, et il n'introduit pas d'interfaces spéciales qui sont étendues d'une nouvelle manière.

5
Peter Taylor

Il y a des inconvénients à autoriser et à interdire une telle syntaxe, et ceux de permettant sont beaucoup plus importants.

Pensez-y.

Séparation de l'interface et de l'implémentation est l'un des idiomes de programmation fondamentaux. Pour cette raison, la syntaxe permettant d'épeler "l'interface implémente quelque chose" serait à peu près aussi mauvaise que celle utilisant le signe plus pour indiquer multiplication d'opérandes.

2
gnat