Я наткнулся на этот фрагмент:
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(long a, long b) {
System.out.println("In long " + (a + b));
}
public static void printSum(double a, long b) {
System.out.println("In doubleLONG " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
Это приведет к ошибке компиляции:
Ошибка: (15, 9) java: ссылка на printSum неоднозначна, как метод printSum (int, double) в ParamTest, так и метод printSum (long, long) в ParamTest match
Как это неоднозначно? Разве в этом случае не следует продвигать только второй параметр, поскольку первый параметр уже является int? Первый параметр не нужно продвигать в этом случае правильно?
Компиляция завершится успешно, если я обновлю код для добавления другого метода:
public static void printSum(int a, long b) {
System.out.println(String.format("%s, %s ", a, b));
}
Позвольте мне расширить, чтобы уточнить. Код ниже приводит к двусмысленности:
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(long a, long b) {
System.out.println("In long " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
Тогда этот код ниже также приводит к неоднозначности:
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(double a, long b) {
System.out.println("In doubleLONG " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
Однако это не приводит к двусмысленности:
public class ParamTest {
public static void printSum(int a, double b) {
System.out.println("In intDBL " + (a + b));
}
public static void printSum(long a, double b) {
System.out.println("In longDBL " + (a + b));
}
public static void main(String[] args) {
printSum(1, 2);
}
}
java
java-8
type-promotion
riruzen
источник
источник
Error:(15, 9) java: reference to printSum is ambiguous both method printSum(int,double) in ParamTest and method printSum(long,long) in ParamTest match
- это не метод, который является неоднозначным, это вызов метода, который является неоднозначным.Ответы:
Я думаю, что это как-то связано со специфическим правилом JLS о 15.12.2.5. Выбор наиболее специфического метода . В нем говорится, что:
Как Java выбирает наиболее конкретный метод, более подробно объясняется текстом:
В вашем примере все методы доступны и применимы для вызова методов, поэтому Java должна определить, какой из них наиболее специфичен .
Для этих методов ни один из них не может быть определен как более конкретный:
Четвертый метод устраняет неоднозначность именно потому, что он удовлетворяет необходимым условиям, чтобы быть наиболее конкретным .
То есть (int, long) может быть передано (int, double), (long, long) или (double, long) без ошибок компиляции.
источник
Это действительно очень интересный вопрос. Давайте шаг за шагом пройдемся по Спецификации языка Java.
Когда компилятор пытается определить потенциально применимые методы, первое, что он делает, - поиск методов, применимых строгим вызовом .
В вашем случае таких методов нет, поэтому следующий шаг - найти методы, применимые Loose Invocation
В этот момент все методы совпадают, поэтому наиболее конкретный метод ( §15.12.2.5 ) выбирается среди методов, которые применимы посредством свободного вызова.
Это ключевой момент, поэтому давайте посмотрим на это внимательно.
(Нас интересует только следующий случай):
Проще говоря, метод более конкретен, если все его типы параметров более специфичны . А также
Выражение
S <: T
означает, чтоS
это подтипT
. Для примитивов у нас есть следующие отношения:Итак, давайте посмотрим на ваши методы и посмотрим, какой из них более конкретен, чем другие.
В этом примере первый параметр метода 1, очевидно, более специфичен, чем первый параметр метода 2 (если вы вызываете их с целочисленными значениями:)
printSum(1, 2)
. Но второй параметр является более специфичным для метода 2 , так какlong < double
. Поэтому ни один из этих методов не является более конкретным, чем другой. Вот почему у вас есть двусмысленность здесь.В следующем примере:
первый тип параметра метода 1 более специфичен, чем в методе 2, поскольку
int < long
второй тип параметра для них одинаков, поэтому метод 1 выбран.источник
double
не более конкретно, чемlong
. А для выбора метода все параметры типа должны быть более конкретными: тип Si более специфичен, чем Ti, для аргумента ei для всех i (1 ≤ i ≤ n, n = k)потому что значение int также может рассматриваться как двойной в Java. Средство
double a = 3
действительно и то же самое с длинным.long b = 3
Вот почему оно создает двусмысленность. Ты звонишьЗапутывает все три метода, потому что все эти три действительны:
Вы можете поставить L в конце, чтобы указать, что это длинное значение. например:
для двойного вам нужно конвертировать его:
также прочитайте комментарий @Erwin Bolwidt
источник