Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

369
Views
¿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 answers
Answer question

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!