method generic example java generics compiler-errors java-8

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.