Я не буду указывать и подробно описывать все правила, используемые компилятором, чтобы решить, какой метод должен быть вызван, поскольку он включает другие критерии. Я сосредоточусь только на критериях параметров метода, которые являются вашим вопросом.
В 15.12.2.5. Choosing the Most Specific Method, у вас есть ценная информация:
Неофициальная интуиция является то, что один метод более точен, чем другой, если любой вызов обрабатывается первым способом может быть передан на другой без ошибка типа компиляции.
В вашем примере здесь является частью JLS, который должен ответить на ваш вопрос:
One fixed-arity member method named m is more specific than another member method of the same name and arity if all of the following conditions hold:
The declared types of the parameters of the first member method are T1, ..., Tn.
The declared types of the parameters of the other method are U1, ..., Un.
If the second method is generic, then let R1 ... Rp (p ≥ 1) be its type parameters, let Bl be the declared bound of Rl (1 ≤ l ≤ p), let A1 ... Ap be the type arguments inferred (§15.12.2.7) for this invocation under the initial constraints Ti << Ui (1 ≤ i ≤ n), and let Si = Ui[R1=A1,...,Rp=Ap] (1 ≤ i ≤ n).
Otherwise, let Si = Ui (1 ≤ i ≤ n).
For all j from 1 to n, Tj <: Sj.
If the second method is a generic method as described above, then Al <: Bl[R1=A1,...,Rp=Ap] (1 ≤ l ≤ p).
Который должен заинтересовать вас For all j from 1 to n, Tj <: Sj
.
Во время компиляции, если было идентифицировано несколько применимых методов, выбирается наиболее конкретная.
Тем не менее, если более чем один метод имеет максимальную специфичность с эффективными типами параметров, компилятор не знает, какой метод следует вызывать. Поэтому он испускает ошибку компиляции.
Вы можете найти эту информацию в JLS : 15.12.2. Compile-Time Step 2: Determine Method Signature:
A method is said to be maximally specific for a method invocation if it is accessible and applicable and there is no other method that is applicable and accessible that is strictly more specific.
If there is exactly one maximally specific method, then that method is in fact the most specific method; it is necessarily more specific than any other accessible method that is applicable. It is then subjected to some further compile-time checks as described in §15.12.3.
It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:
- If all the maximally specific methods have override-equivalent (§8.4.2) signatures, then:
If exactly one of the maximally specific methods is not declared abstract, it is the most specific method.
Otherwise, if all the maximally specific methods are declared abstract, and the signatures of all of the maximally specific methods have the same erasure (§4.6), then the most specific method is chosen arbitrarily among the subset of the maximally specific methods that have the most specific return type.
However, the most specific method is considered to throw a checked exception if and only if that exception or its erasure is declared in the throws clauses of each of the maximally specific methods.
- Otherwise, we say that the method invocation is ambiguous, and a
compile-time > error occurs.
Если применить эти правила к вашим трем примерам (я изменил порядок, чтобы начать с делами, которые собирают хорошо и закончить с случае ошибки компиляции) ,
1) Один специфический метод максимально нашел
class MyClass{
public static void myMethod(int i){
System.out.println("myMethod1(int)");
}
public static void myMethod(double a){
System.out.println("myMethod2(int)");
}
}
class Demo{
public static void main(String args[]){
MyClass.myMethod(100);
}
}
компилятор видит метод с идеальным соответствия: myMethod(int i)
значение, переданное является int
. Он прекрасно компилируется.
2) Один специфический метод максимально найден
class MyClass{
public static void myMethod(int i){
System.out.println("myMethod1(int)");
}
public static void myMethod(double a){
System.out.println("myMethod2(int)");
}
}
class Demo{
public static void main(String args[]){
byte b=10;
MyClass.myMethod(b);
}
}
Компилятор видит метод с более более высокой специфичностью, чем другая.
Неявное преобразование от byte
к int
действительно более конкретное, чем неявное преобразование от byte
до double
в соответствии с правилами расширения примитивных преобразований.
Мы могли бы проверить, что void myMethod(int i)
более специфичен, чем void myMethod(double a)
если вызов обрабатывается первым способом может быть передан на другой без ошибок типа во время компиляции.
myMethod(3);
прилагается к void myMethod(double x)
компилируется в порядке.
Но myMethod(double)3);
, примененный к void myMethod(int y)
, производит ошибку компиляции.
Так был найден уникальный максимально конкретный метод: void myMethod(int i)
.
Компиляция в порядке.
3) Уникальный максимально конкретный метод не нашел
class Demo{
public static void myMethod(int y, double x){}
public static void myMethod(double x,int y){}
public static void main(String args[]){
byte b=10;
myMethod(b,b);
}
}
Компилятор видит два способа, где никто не имеет специфичность выше, чем другой.
Во-первых, в обоих случаях требуется неявное преобразование эффективных типов параметров в параметры объявленных типов методов.
Но в обоих случаях специфика одинакова.
Мы могли бы проверить, что void myMethod(int y, double x)
как конкретен myMethod(double x,int y)
если вызов обрабатывается любым способом, не может быть передан на другой без ошибок типа во время компиляции.
myMethod(double)3,4);
применяется к void myMethod(int y, double x)
выдает ошибку компиляции как int
переменная не может принимать значение double
.
И myMethod(3,(double)4);
, примененный к void myMethod(double x,int y)
, производит ошибку компиляции по той же причине.
Не найдено уникального максимально конкретного метода. Поэтому компилятор не может догадаться, какой метод следует вызывать. Возникает ошибка компиляции.
Короткий ответ: Java работает таким образом в соответствии с JLS. http://stackoverflow.com/questions/30776256/casting-rules-for-primitive-types-in-java –
@ eug.nikolaev на самом деле этот ответ не отвечает на текущий вопрос, который шире, чем расширяющийся примитив переходы имеют значение. Это дает довольно интересные указатели. – davidxxx