Alors que le premier exemple compile, il va générer un avertissement de conversion non vérifiée :
// Sécurité du type : le type de retour List pour foo() à partir du type C nécessite
// une conversion non vérifiée pour se conformer à List
public List foo()
{
return null;
}
Ce qui se passe ici est que en déclarant des paramètres de type, A.foo()
et B.foo()
sont des méthodes génériques. Ensuite, l'annulation de C.foo()
omet ce paramètre de type. C'est similaire à l'utilisation d'un type brut, essentiellement "optant" pour ne pas vérifier le type générique pour cette signature de méthode. Cela fait que le compilateur utilise les effacements des méthodes héritées à la place : List foo()
et List foo()
deviennent tous les deux List foo()
, ce qui peut donc être implémenté par C.foo()
.
Vous pouvez voir que en gardant le paramètre de type dans la déclaration de C.foo()
, il y aura l'erreur du compilateur attendue à la place :
// Le type de retour est incompatible avec A.foo()
public List foo()
{
return null;
}
De même, si l'une des méthodes d'interface ne déclare pas de paramètre de type, alors l'omission d'un paramètre de type dans l'annulation échoue à se «désigner» pour la vérification du type générique pour cette méthode, et le type de retour List
reste incompatible.
Ce comportement est couvert dans JLS §8.4.2 :
La notion de subsignature est conçue pour exprimer une relation entre deux méthodes dont les signatures ne sont pas identiques, mais dans lesquelles l'une peut remplacer l'autre. Plus précisément, cela permet à une méthode dont la signature n'utilise pas de types génériques de remplacer n'importe quelle version générifiée de cette méthode. Ceci est important pour que les concepteurs de bibliothèques puissent librement générer des méthodes indépendamment des clients qui définissent des sous-classes ou des sous-interfaces de la bibliothèque.
Le FAQ sur les génériques d'Angelika Langer élargit ce comportement dans sa section Un méthode non générique peut-elle remplacer une méthode générique ? :
Explorons maintenant un exemple où les méthodes de sous-type non génériques remplacent les méthodes de supertype génériques. Les méthodes de sous-type non génériques sont considérées comme des versions de remplacement des méthodes de supertype génériques si les effacements des signatures sont identiques.
Exemple (de méthodes de sous-type non génériques remplaçant les méthodes de supertype génériques) :
class Super {
public void set( T arg) { ... }
public T get() { ... }
}
class Sub extends Super {
public void set( Object arg) { ... } // remplace
public Object get() { ... } // remplace avec un avertissement non vérifié
}
attention : get() dans Sub remplace get() dans Super ;
le type de retour nécessite une conversion non vérifiée
trouvé : Object
requis : T
public Object get() {
Ici, les méthodes de sous-type ont des signatures, à savoir set(Object)
et get()
, qui sont identiques aux effacements des méthodes de supertype. Ces signatures érodées sont considérées comme des équivalents de remplacement.
Il y a une imperfection dans le cas de la méthode get
: nous recevons une avertissement non vérifié parce que les types de retour ne sont pas vraiment compatibles. Le type de retour de la méthode de sous-type get
est Object
, le type de retour de la méthode de supertype get est un paramètre de type non borné. Le type de retour de la méthode de sous-type n'est ni identique à celui du supertype et n'est pas un sous-type de celui-ci ; dans les deux situations le compilateur accepterait volontiers les types de retour comme compatibles. Au lieu de cela, le type de retour de la méthode de sous-type Object
est convertible en le le type de retour de la méthode de supertype par le biais d'une conversion non vérifiée. Un avertissement non vérifié indique qu'une vérification de type est nécessaire que ni le compilateur ni la machine virtuelle ne peuvent effectuer. En d'autres termes, l'opération non vérifiée n'est pas sûre en termes de type. En cas de types de retour convertibles, quelqu'un devrait s'assurer que le la valeur de retour de la méthode de sous-type est compatible avec le supertype le type de retour de la méthode, mais personne hormis le programmeur ne peut garantir cela.