example - java generic method
Java 8: la referencia a[método] es ambigua (2)
Parece que esta es una incompatibilidad conocida.
Vea la sección "Área: Herramientas / javac" de este artículo. Y este error .
Sinopsis
El siguiente código que se compiló, con advertencias, en JDK 7 no se compilará en JDK 8:
import java.util.List;
class SampleClass {
static class Baz<T> {
public static List<Baz<Object>> sampleMethod(Baz<Object> param) {
return null;
}
}
private static void bar(Baz arg) {
Baz element = Baz.sampleMethod(arg).get(0);
}
}
La compilación de este código en JDK 8 produce el siguiente error:
SampleClass.java:12: error:incompatible types: Object cannot be converted to Baz
Baz element = Baz.sampleMethod(arg).get(0);
Note: SampleClass.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
En este ejemplo, se pasa un tipo sin formato al método sampleMethod (Baz) que se aplica mediante subtipos (consulte JLS, Java SE 7 Edition, sección 15.12.2.2).
Una conversión sin marcar es necesaria para que el método sea aplicable, por lo que su tipo de retorno se borra (consulte JLS, Java SE 7 Edition, sección 15.12.2.6). En este caso, el tipo de retorno de sampleMethod (Baz) es java.util.List en lugar de java.util.List> y, por lo tanto, el tipo de retorno de get (int) es Object, que no es compatible con Baz.
Esta pregunta ya tiene una respuesta aquí:
¿Alguien entiende por qué el siguiente código se compilará bien en Java 7 y versiones posteriores, pero falla con Java 8?
public static void main(String[] args) throws Exception {
put(get("hello"));
}
public static <R> R get(String d) {
return (R)d;
}
public static void put(Object o) {
System.err.println("Object " + o);
}
public static void put(CharSequence c) {
System.err.println("CharSequence " + c);
}
public static void put(char[] c) {
System.err.println("char[] " + c);
}
El método get tiene un tipo de retorno genérico. En JDK 7 y más abajo, esta compilación está bien y se elige el método put con el parámetro Object. En JDK 8, esto no se puede compilar, lo que indica que el método put es ambiguo.
Aparentemente, JDK 8 omite el método del parámetro Objeto y encuentra los dos últimos métodos del subobjetivo del objeto y se queja del mismo (es decir, si agrega otro método de colocación con algún otro tipo de parámetro, el compilador cambiará y se quejará por el último último). dos métodos)
Esto parece un error.
Su problema es un efecto secundario de la Inferencia generalizada de tipo objetivo , una mejora en Java 8.
¿Qué es la Inferencia de tipo objetivo?
Tomemos su método de ejemplo,
public static <R> R get(String d) {
return (R)d;
}
Ahora, en el método anterior, el compilador no puede resolver el parámetro genérico R
porque no hay ningún parámetro con R
Entonces, introdujeron un concepto llamado Target-type Inference
, que permite inferir el parámetro en función del parámetro de asignación.
Así que, si lo haces,
String str = get("something"); // R is inferred as String here
Number num = get("something"); // R is inferred as Number here
Esto funciona bien en Java 7. Pero lo siguiente no ,
put(get("something");
static void Put(String str) {} //put method
Porque la inferencia de tipos funcionó solo para asignaciones directas.
Si no hay una asignación directa, entonces el tipo genérico se infirió como Object
.
Entonces, cuando compiló el código con Java 7, se put(Object)
su método put(Object)
sin ningún problema.
Lo que hicieron en Java 8.
Mejoraron la inferencia de tipos para inferir el tipo a partir de llamadas a métodos y llamadas a métodos encadenados
Más detalles sobre ellos here y here
Así que ahora, puede llamar directamente a put(get("something"))
y el tipo genérico se deducirá en función del parámetro del método put()
.
Pero como saben, los métodos, put(Charsequence)
y put(char[])
coinciden con los argumentos. Así que ahí está la ambigüedad.
¿Fijar?
Simplemente dile al compilador exactamente lo que quieres,
put(TestClass.<CharSequence>get("hello")); // This will call the put(CharSequence) method.