Eu quero criar duas funções, digamos
long min(long...); int min(int...);
Mas quando eu tento invocar o segundo, ou seja, min(1, 5)
, recebo uma chamada de método ambígua
Existe solução alternativa, exceto renomear?
É um bug conhecido
O comportamento que você descreve é um bug que foi corrigido com o Java 7. Veja os detalhes nas notas de lançamento , seção “Mudanças na Seleção de Método Mais Variável Variável”.
A razão pela qual deve compilar
A arriedade variável vem por último na determinação do método mais específico. As regras para determinar qual método vararg se aplica quando existem várias são definidas no JLS 15.12.2.4 – aqui está um extrato:
Um método de membro de aridade variável chamado m é mais específico do que outro método de membro de aridade de variável com o mesmo nome se:
– […]
– Um método membro possui k parâmetros e o outro tem n parâmetros, onde n ≥ k e:
- Os tipos dos parâmetros do primeiro método são U1, …, Uk-1, Uk [].
- Os tipos dos parâmetros do outro método são T1, …, Tn-1, Tn [].
- Para todo j de 1 a n, Uj <: Tj
No seu caso, k = n, e U1[] = int[]
e T1[] = long[]
então a determinação pode ser feita se int <: long
ou o contrário.
Em outras palavras, o tipo considerado não é int[]
vs. long[]
mas int
vs long
. E acontece que int <: long
então o método int...
deve ser escolhido e deve compilar.
Conclusão:
O código deve (e faz) compilar bem com o Java 7, mas não compilará com o Java 5 ou 6. O código abaixo imprime int
com o Java 7:
public class Test1 { public static void main(String[] args) { new Test1().m(1, 2); } int m(int... i) { System.out.println("int"); return 0; } long m(long... i) { System.out.println("long"); return 0; } }
O problema é quando você invoca esses methods com um integer
, nenhum dos methods fornece correspondência exata para o argumento, como você usou var-args
. Além disso, ambos os var-args
podem ter valores int
separados por vírgulas como argumento. Daí o erro de ambiguous method
.
Quando você chama o método sobrecarregado, o Compiler
escolhe a exact match
primeiro. Então, o nearest type
a ser lançado.
Agora, como var-args
é apenas uma array
, o compilador não pode decidir qual array usar ao passar um valor integer
. Como, nenhum dos arrays pode ser considerado como exact match
ou nearest conversion
. Portanto, é necessário o método elegível para a chamada.
Existem muito mais regras sobre a method invocation
do method invocation
em caso de Overloading
. Você pode aprender com a Java Language Specification
.
Como na resposta de @assylias, este problema foi corrigido no Java 7. Mas não funcionará na versão Java <7.
Tente isso
public class Test { /** * @param args the command line arguments */ public static void main(String[] args) { new Test().m(100L,512L); new Test().m(100,512); } int m(int... i) { System.out.println("int"); return 0; } long m(long... i) { System.out.println("long"); return 0; } }
Essas assinaturas de método são exclusivas e são sobrecargas de método válidas.
O problema deve estar no argumento de chamada do método. Meu palpite é que você está chamando o método com um literal, como:
min(100)
E isso não acontece porque 100 é um literal inteiro, mas é automaticamente convertido para um longo.
Desambiguar as chamadas de método usando L no final de literais longos deve corrigir o problema:
min(100L)
Além disso, você poderia tornar as chamadas explícitas usando o Java Object Integer e Long e deixar a autoboxing cuidar da conversão para tipos primitivos:
min(new Long(100)) min(new Integer(100))