Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

359
Vistas
¿Por qué esta llamada de método genérico de Java es ambigua cuando solo un método es válido cuando está separado?

Estoy tratando de entender por qué el compilador no puede resolver la llamada al método de bar . Esperaría que bar(Xyz::new) seleccione siempre bar(Supplier) ya que bar(T extends Xyz) nunca puede coincidir debido al límite superior en Xyz .

 public <T extends Xyz> void foo(T s) {} public <T extends Xyz> void bar(T s) {} public <T extends Xyz> void bar(Supplier<T> s) {} public void example() { foo(Xyz::new); // not valid (does not extend Xyz) bar((Supplier<Xyz>) Xyz::new); // valid (explicitly a Supplier) bar(Xyz::new); // ambiguous - but only one method is valid? } public static class Xyz {}

Si bar(T) no es aplicable, incluso cuando está solo (como se muestra con foo(T) ), entonces seguramente la única opción es bar(Supplier) haciendo de esto una sobrecarga no ambigua.

¿Por qué la llamada de bar es ambigua, especialmente cuando las llamadas foo y bar(T) no son resoluciones válidas en sí mismas?

Ejemplo ejecutable del código anterior: https://www.jdoodle.com/ia/kqP

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Tiene razón en que un compilador más inteligente debería poder resolver esto sin ambigüedades.

La forma en que Java resuelve las invocaciones de métodos es compleja . Estádefinido por el JLS , y lo hago 7500 palabras simplemente para determinar cómo resolver un método. Pegado en un editor de texto, tenía 15 páginas.

El enfoque general es:

  1. Tiempo de compilación Paso 1: determinar el tipo de búsqueda (no hay problema aquí)
  2. Paso 2 en tiempo de compilación: determinar la firma del método
    1. Identificar métodos potencialmente aplicables
    2. Fase 1: Identificar métodos de aridad coincidentes aplicables por invocación estricta
    3. Fase 2: Identificar métodos de aridad coincidentes aplicables por invocación suelta
    4. Fase 3: Identificar métodos aplicables por invocación de aridad variable
    5. Elegir el método más específico
    6. Tipo de invocación de método
  3. Compile-Time Paso 3: ¿Es apropiado el método elegido?

No entiendo ni cerca de todos los detalles y cómo se relaciona con su caso específico. Si desea sumergirse en él, ya he vinculado la especificación completa. Esperemos que esta explicación sea lo suficientemente buena para sus propósitos:

La ambigüedad se determina en el paso 2.6, pero todavía hay una verificación adicional de adecuación en el paso 3. Su método foo debe estar fallando en el paso 3. Su método bar nunca llega tan lejos porque el compilador aún considera que ambos métodos son posibilidades válidas. Un ser humano puede tomar la determinación de que la inadecuación resuelve la ambigüedad, pero ese no es el orden en que el compilador hace las cosas. Solo podía especular por qué: el rendimiento podría ser un factor.

Su código está operando en la intersección de los genéricos, la sobrecarga y las referencias de métodos, los cuales se introdujeron en diferentes momentos; no me sorprende enormemente que el compilador tenga problemas.

over 4 years ago · Santiago Trujillo Denunciar

0

Su problema es principalmente un problema de inferencia de tipo que un problema de método ambiguo:

 public <T extends Xyz> void bar(T s) {} // bar(Xyz) public void bar(String s) {} public <T extends Zyx> void bar(T s) {} // bar(Zyx) public <T extends Xyz> void bar(Supplier<T> s) {} public static class Xyz {} public static class Zyx {}

Si utiliza:

 bar(new Xyz()); // ok bar("a"); // ok bar(new Zyx()); // ok bar((Supplier<Xyz>) Xyz::new); // ok bar(Xyz::new); // ambiguous

Obtiene este error (probado con Java 17) que no se trata de la lambda, sino del tipo T : no se puede inferir tipo-variable (s) T

 both method <T#1>bar(T#1) in Example and method <T#2>bar(Supplier<T#2>) in Example match where T#1,T#2 are type-variables: T#1 extends Zyx declared in method <T#1>bar(T#1) T#2 extends Xyz declared in method <T#2>bar(Supplier<T#2>) Example.java:18: error: incompatible types: cannot infer type-variable(s) T

Java no es lo suficientemente inteligente como para encontrar el tipo T concreto en este caso, y tienes que ayudarlo:

 Example.<Xyz>bar(Xyz::new);

Traté de buscar en el JLS, impulsado por la respuesta de Michael, y la sección que debería responder mejor a su pregunta es la 18.5.1. Inferencia de la aplicabilidad de la invocación .

Tuve el mismo tipo de errores que ocurrían con frecuencia con Java 7 y Colecciones:

 public static <T extends Zyx> void bar(java.util.List<T> s) {} // bar(Zyx) public static <T extends Zyx> void bar(T s) {} // bar(List) bar(new Zyx()); bar(java.util.Collections.emptyList());

Lo peor de todo es que Eclipse no tenía problemas, mientras que javac fallaba.

Supongo que en el caso de las lambdas, el compilador no infiere el tipo T del "Xyz".

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda