Considérez les deux classes et l'interface suivantes:
public class Class1 {}
public class Class2 {}
public interface Interface1 {}
Pourquoi le deuxième appel à mandatory
appeler la méthode surchargée avec Class2
, si getInterface1
et Interface1
n'a aucune relation avec Class2
?
public class Test {
public static void main(String[] args) {
Class1 class1 = getClass1();
Interface1 interface1 = getInterface1();
mandatory(getClass1()); // prints "T is not class2"
mandatory(getInterface1()); // prints "T is class2"
mandatory(class1); // prints "T is not class2"
mandatory(interface1); // prints "T is not class2"
}
public static <T> void mandatory(T o) {
System.out.println("T is not class2");
}
public static <T extends Class2> void mandatory(T o) {
System.out.println("T is class2");
}
public static <T extends Class1> T getClass1() {
return null;
}
public static <T extends Interface1> T getInterface1() {
return null;
}
}
Je comprends que Java 8 a rompu la compatibilité avec Java 7:
$ /usr/lib/jvm/java-8-openjdk-amd64/bin/javac -source 1.7 -target 1.7 *java; /usr/lib/jvm/java-8-openjdk-amd64/bin/java Test
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
T is not class2
T is not class2
T is not class2
T is not class2
Et avec Java 8 (également testé avec 11 et 13):
$ /usr/lib/jvm/java-8-openjdk-amd64/bin/javac *java; /usr/lib/jvm/java-8-openjdk-amd64/bin/java Test
T is not class2
T is class2
T is not class2
T is not class2
Réponses:
Les règles d'inférence de type ont fait l'objet d'une refonte importante dans Java 8, notamment l'inférence de type cible a été considérablement améliorée. Ainsi, alors qu'avant Java 8, le site d'arguments de méthode ne recevait aucune inférence, par défaut sur le type effacé (
Class1
pourgetClass1()
etInterface1
pourgetInterface1()
), dans Java 8, le type applicable le plus spécifique est déduit. Le JLS pour Java 8 a introduit un nouveau chapitre Chapitre 18. Type Inférence qui manque dans JLS pour Java 7.Le type applicable le plus spécifique pour
<T extends Interface1>
est<X extends RequiredClass & BottomInterface>
, oùRequiredClass
est une classe requise par un contexte, etBottomInterface
est un type inférieur pour toutes les interfaces (y comprisInterface1
).Remarque: Chaque type Java peut être représenté par
SomeClass & SomeInterfaces
. PuisqueRequiredClass
est un sous-type deSomeClass
, etBottomInterface
est un sous-type deSomeInterfaces
,X
est un sous-type de chaque type Java. Par conséquent, ilX
s'agit d'un type inférieur Java.X
correspond à la fois aux signatures de méthodespublic static <T> void mandatory(T o)
et est du type Java bas.public static <T extends Class2> void mandatory(T o)
X
Ainsi, selon le §15.12.2 ,
mandatory(getInterface1())
appelle la surcharge demandatory()
méthode la plus spécifique , qui estpublic static <T extends Class2> void mandatory(T o)
depuis<T extends Class2>
plus spécifique que<T>
.Voici comment vous pouvez spécifier explicitement le
getInterface1()
paramètre type pour qu'il renvoie le résultat qui correspond à lapublic static <T extends Class2> void mandatory(T o)
signature de la méthode:Le type applicable le plus spécifique pour
<T extends Class1>
est<Y extends Class1 & BottomInterface>
, oùBottomInterface
est un type inférieur pour toutes les interfaces.Y
allumettespublic static <T> void mandatory(T o)
signature de la méthode, mais il ne correspond pas à lapublic static <T extends Class2> void mandatory(T o)
signature de la méthode carY
il ne s'étend pasClass2
.Donc
mandatory(getClass1())
appellepublic static <T> void mandatory(T o)
méthode.Contrairement à with
getInterface1()
, vous ne pouvez pas spécifier explicitement legetClass1()
paramètre type pour lui faire retourner le résultat qui correspond à lapublic static <T extends Class2> void mandatory(T o)
signature de la méthode:la source