Этот вопрос действительно о разрешении неоднозначных перегрузок, а не о полиморфизме во время выполнения (потому что выбор перегруженного метода для вызова выполняется в время компиляции ).
Разрешение метода - сложная вещь, и в этом случае то, будет ли код компилироваться вообще, зависит от того, какие типы используются. Существует множество ситуаций, в которых код будет компилироваться. См. Код ниже (обратите внимание, что String implements CharSequence
):
public class MyClass {
MyClass(CharSequence charSeq) {
System.out.println("CharSequence");
}
MyClass(String s) {
System.out.println("String");
}
public static void main(String[] args) {
new MyClass(null); // prints "String"
new MyClass(""); // prints "String"
new MyClass((CharSequence) null); // prints "CharSequence"
new MyClass((CharSequence) ""); // prints "CharSequence"
}
}
Обратите внимание, что без приведения выбрана перегрузка String
. Это в точности как указано в JLS:
Если более одного метода-члена доступны и применимы к вызову метода, необходимо выбрать один, чтобы предоставить дескриптор для отправки метода во время выполнения. Язык программирования Java использует правило, согласно которому выбирается самый специфический метод.
A String
is-a CharSequence
, но не все CharSequence
is-a String
. Следовательно, String
является более точным , чем CharSequence
, поэтому в приведенном выше примере выбрана перегрузка String
.
Стоит отметить, что этот точный вопрос (по сути) появился в замечательных Java Puzzlers (настоятельно рекомендуется), в частности Puzzle 46 : Случай запутанного конструктора
Процесс разрешения перегрузки Java работает в два этапа. На первом этапе выбираются все методы или конструкторы, которые доступны и применимы. На втором этапе выбираются наиболее специфичные методов или конструкторов, выбранных на первом этапе. Один метод или конструктор менее специфичен, чем другой, если он может принимать любые параметры, переданные другому
Ключом к пониманию этой загадки является то, что тест, для которого метод или конструктор является наиболее специфичным, не использует фактические параметры : параметры, появляющиеся в вызове. Они используются только для определения того, какие перегрузки применимы. Как только компилятор определяет, какие перегрузки применимы и доступны, он выбирает наиболее специфическую перегрузку, используя только формальные параметры : параметры, указанные в объявлении.
Я закрою цитатой из Effective Java 2nd Edition , Item 41: Используйте разумную перегрузку :
Правила, определяющие, какая перегрузка выбрана, чрезвычайно сложны. Они занимают тридцать три страниц в спецификации языка, и лишь немногие программисты понимают все их тонкости.
Само собой разумеется, эта книга также настоятельно рекомендуется .
Смотри также