Considere las siguientes dos clases e interfaces:
public class Class1 {}
public class Class2 {}
public interface Interface1 {}¿Por qué la segunda llamada para mandatoryinvocar el método sobrecargado con Class2, si getInterface1y Interface1no tiene relación 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;
    }
}Entiendo que Java 8 rompió la compatibilidad con 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 class2Y con Java 8 (también probado con 11 y 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
Respuestas:
Las reglas de inferencia de tipos han recibido una revisión importante en Java 8, más notablemente la inferencia de tipos de destino se ha mejorado mucho. Entonces, mientras que antes de Java 8 el sitio de argumento del método no recibió ninguna inferencia, por defecto al tipo borrado (
Class1porgetClass1()yInterface1paragetInterface1()), en Java 8 se infiere el tipo aplicable más específico. JLS para Java 8 introdujo un nuevo capítulo Capítulo 18. Inferencia de tipo que falta en JLS para Java 7.El tipo aplicable más específico para
<T extends Interface1>es<X extends RequiredClass & BottomInterface>, dondeRequiredClasses una clase requerida por un contexto, yBottomInterfacees un tipo inferior para todas las interfaces (incluidasInterface1).Nota: cada tipo de Java se puede representar como
SomeClass & SomeInterfaces. Dado queRequiredClasses un subtipo deSomeClass, yBottomInterfacees un subtipo deSomeInterfaces,Xes un subtipo de cada tipo de Java. Por lo tanto,Xes un tipo de fondo Java.Xpartidos ambospublic static <T> void mandatory(T o)ypublic static <T extends Class2> void mandatory(T o)métodos firmas yaXes Java tipo de fondo.Así, de acuerdo con §15.12.2 ,
mandatory(getInterface1())llama a la sobrecarga específica mayor parte demandatory()método, que espublic static <T extends Class2> void mandatory(T o)ya<T extends Class2>es más específico que<T>.Aquí se explica cómo puede especificar explícitamente el
getInterface1()parámetro de tipo para que devuelva el resultado que coincide con lapublic static <T extends Class2> void mandatory(T o)firma del método:El tipo aplicable más específico para
<T extends Class1>es<Y extends Class1 & BottomInterface>, dondeBottomInterfacees un tipo inferior para todas las interfaces.Ycoincide con lapublic static <T> void mandatory(T o)firma del método, pero no coincide con lapublic static <T extends Class2> void mandatory(T o)firma del método yaYque no se extiendeClass2.Entonces
mandatory(getClass1())llamapublic static <T> void mandatory(T o)método.A diferencia de
getInterface1(), no puede especificar explícitamente elgetClass1()parámetro de tipo para que devuelva el resultado que coincide con lapublic static <T extends Class2> void mandatory(T o)firma del método:fuente