Je me demande s’il existe une raison particulière en Java d’utiliser toujours "extends
" plutôt que "implements
" pour définir les limites de typeparameters.
Exemple:
public interface C {}
public class A<B implements C>{}
est interdit mais
public class A<B extends C>{}
est correct. Quelle est la raison de ceci?
Il n'y a pas de différence sémantique dans le langage de contrainte générique selon qu'une classe "implémente" ou "étend". Les possibilités de contrainte sont 'étend' et 'super' - c'est-à-dire que cette classe fonctionne avec assignable à celui-ci ou qu'elle est assignable à partir de celui-ci.
La réponse est dans ici :
Pour déclarer un paramètre de type lié, indiquez le nom du paramètre, suivi du mot clé
extends
, suivi de sa borne supérieure […]. Notez que, dans ce contexte, étend est utilisé dans un sens général pour signifier soitextends
(comme dans les classes), soitimplements
(comme dans les interfaces).
Donc, voilà, c'est un peu déroutant et Oracle le sait.
Probablement parce que pour les deux côtés (B et C), seul le type est pertinent, pas la mise en œuvre. Dans votre exemple
public class A<B extends C>{}
B peut aussi être une interface. "extend" est utilisé pour définir des sous-interfaces ainsi que des sous-classes.
interface IntfSub extends IntfSuper {}
class ClzSub extends ClzSuper {}
Je pense généralement que 'Sub étend Super' en tant que ' Sub est semblable à Super , mais avec des fonctionnalités supplémentaires', et 'Clz implémente Intf' en tant que ' Clz est une réalisation de Intf '. Dans votre exemple, cela correspondrait à:Bressemble àC, mais avec des fonctionnalités supplémentaires. Les capacités sont pertinentes ici, pas la réalisation.
Il se peut que le type de base soit un paramètre générique, de sorte que le type réel peut être une interface d'une classe. Considérer:
class MyGen<T, U extends T> {
De même, du point de vue du code client, les interfaces sont presque impossibles à distinguer des classes, alors que pour les sous-types, il est important.
Voici un exemple plus compliqué où les extensions sont autorisées et éventuellement ce que vous voulez:
public class A<T1 extends Comparable<T1>>
C'est en quelque sorte arbitraire quel terme utiliser. Cela aurait pu être l'un ou l'autre. Peut-être que les concepteurs de langage ont pensé que "étend" était le terme le plus fondamental et "implémentait" le cas particulier des interfaces.
Mais je pense que implements
aurait un peu plus de sens. Je pense que cela communique plus que les types de paramètres ne doivent pas nécessairement être dans une relation d'héritage, ils peuvent être dans n'importe quel type de relation de sous-type [].
Le glossaire Java exprime un vue similaire .
Le terme "étend" dans ce contexte, signifie comme les implémentations dans les interfaces et s'étend dans les classes. Voici plus d'explication
Nous avons l'habitude de
class ClassTypeA implements InterfaceTypeA {}
class ClassTypeB extends ClassTypeA {}
et toute légère déviation de ces règles nous confond grandement.
La syntaxe d'un type lié est définie comme suit:
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
( JLS 12> 4.4. Variables de type> TypeBound
)
Si nous devions le changer, nous ajouterions sûrement le cas implements
TypeBound:
extends TypeVariable
extends ClassType {AdditionalBound}
implements InterfaceType {AdditionalBound}
et se retrouver avec deux clauses traitées de manière identique
ClassOrInterfaceType:
ClassType
InterfaceType
( JLS 12> 4.3. Types et valeurs de référence> ClassOrInterfaceType
)
sauf que nous aurions également besoin de nous occuper de implements
, ce qui compliquerait les choses davantage.
Je crois que c'est la raison principale pour laquelle extends ClassOrInterfaceType
est utilisé à la place de extends ClassType
et implements InterfaceType
- pour que les choses restent simples dans le concept compliqué. Le problème est que nous n'avons pas le bon mot pour couvrir à la fois extends
et implements
et nous ne voulons absolument pas en introduire un.
<T is ClassTypeA>
<T is InterfaceTypeA>
Bien que extends
crée des dégâts quand il s’agit d’une interface, il s’agit d’un terme plus large qui peut être utilisé pour décrire les deux cas. Essayez d’accorder votre esprit au concept de extension d’un type (non prolonger une classe, ne pas implémenter une interface). Vous limitez un paramètre de type par un autre type et le type de ce type importe peu. Il importe seulement que ce soit sa borne supérieure et que c'est son supertype .