Betrachten Sie die folgenden zwei Klassen und Schnittstellen:
public class Class1 {}
public class Class2 {}
public interface Interface1 {}
Warum ruft der zweite Aufruf mandatory
die überladene Methode auf Class2
, wenn getInterface1
und Interface1
hat keine Beziehung zu 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;
}
}
Ich verstehe, dass Java 8 die Kompatibilität mit Java 7 gebrochen hat :
$ /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
Und mit Java 8 (auch mit 11 und 13 getestet):
$ /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
Antworten:
Die Regeln für die Typinferenz wurden in Java 8 grundlegend überarbeitet. Insbesondere die Zieltypinferenz wurde erheblich verbessert. Während vor Java 8 die Methodenargument-Site keine Inferenz erhielt, standardmäßig der gelöschte Typ (
Class1
fürgetClass1()
undInterface1
fürgetInterface1()
), wird in Java 8 der spezifischste anwendbare Typ abgeleitet. Mit JLS für Java 8 wurde ein neues Kapitel Kapitel 18 eingeführt. Typinferenz , die in JLS für Java 7 fehlt.Der spezifischste anwendbare Typ für
<T extends Interface1>
ist<X extends RequiredClass & BottomInterface>
, woRequiredClass
eine Klasse für einen Kontext erforderlich ist, undBottomInterface
ist ein unterer Typ für alle Schnittstellen (einschließlichInterface1
).Hinweis: Jeder Java-Typ kann als dargestellt werden
SomeClass & SomeInterfaces
. DaRequiredClass
es sich um einen Untertyp vonSomeClass
und einenBottomInterface
Untertyp von handeltSomeInterfaces
,X
handelt es sich um einen Untertyp jedes Java-Typs. DaherX
handelt es sich um einen Java-Bodentyp.X
Entspricht beidenpublic static <T> void mandatory(T o)
undpublic static <T extends Class2> void mandatory(T o)
Methodensignaturen, daX
es sich um den unteren Java-Typ handelt.Also, nach §15.12.2 ,
mandatory(getInterface1())
ruft die spezifischste Überlastung dermandatory()
Methode, die istpublic static <T extends Class2> void mandatory(T o)
seit<T extends Class2>
spezifischer als ist<T>
.So können Sie den
getInterface1()
Typparameter explizit angeben , damit das Ergebnis zurückgegeben wird, das derpublic static <T extends Class2> void mandatory(T o)
Methodensignatur entspricht:Der spezifischste anwendbare Typ für
<T extends Class1>
ist<Y extends Class1 & BottomInterface>
, woBottomInterface
ein unterer Typ für alle Schnittstellen ist.Y
Entspricht derpublic static <T> void mandatory(T o)
Methodensignatur, stimmt jedoch nicht mit derpublic static <T extends Class2> void mandatory(T o)
Methodensignatur überein , daY
sie nicht erweitert wirdClass2
.Also
mandatory(getClass1())
ruftpublic static <T> void mandatory(T o)
Methode auf.Im Gegensatz zu with
getInterface1()
können Sie dengetClass1()
Typparameter nicht explizit angeben , damit das Ergebnis zurückgegeben wird, das derpublic static <T extends Class2> void mandatory(T o)
Methodensignatur entspricht:quelle