Почему вывод такой? - PullRequest
       19

Почему вывод такой?

13 голосов
/ 14 июня 2010
class Another {
    public void method(Object o) {
        System.out.println("This is in method which takes object");
    }
    public void method(String s) {
        System.out.println("This is method which takes string");
    }
}

public class NewClass {
    public static void main(String args[]) {
        Another an = new Another();
        an.method(null);
    }
}

Когда я пытаюсь выполнить это, я получаю

Это метод, который принимает строку

в качестве вывода.Почему бы не "Это в методе, который принимает объект"?Объект также может иметь значение null, а string также может иметь значение null, почему он не вызывает первый метод?

Ответы [ 4 ]

25 голосов
/ 14 июня 2010

Согласно Спецификации языка Java , в таких случаях перегруженных методов, где оба метода могут обрабатывать предоставленные аргументы, выбирается метод с более конкретным аргументом. Поскольку String более конкретно, чем Object (String расширяет Object), void method(String) выбирается и вызывается.

7 голосов
/ 14 июня 2010

Это точно как указано в JLS:

JLS 15.12.2.5 Выбор наиболее специфического метода

Если более одного метода-члена доступны и применимы для вызова метода, необходимо выбрать один, чтобы предоставить дескриптор для отправки метода во время выполнения. Язык программирования Java использует правило, согласно которому выбирается самый специфический метод.

A String - это Object, но не все Object - это String. Следовательно, String является более конкретным , чем Object, поэтому в приведенном выше примере выбрана перегрузка String.


Стоит отметить, что этот точный вопрос (по сути) появился в замечательных Java Puzzlers (настоятельно рекомендуется), в частности Puzzle 46 : Случай запутанного конструктора

Процесс разрешения перегрузки Java работает в два этапа. На первом этапе выбираются все методы или конструкторы, которые доступны и применимы. На втором этапе выбирается наиболее специфичный методов или конструкторов, выбранных на первом этапе. Один метод или конструктор менее специфичен, чем другой, если он может принимать любые параметры, переданные другому

Ключом к пониманию этой загадки является то, что тест, для которого метод или конструктор является наиболее специфичным, не использует фактические параметры : параметры, появляющиеся в вызове. Они используются только для определения того, какие перегрузки применимы. Как только компилятор определяет, какие перегрузки применимы и доступны, он выбирает наиболее специфическую перегрузку, используя только формальные параметры : параметры, указанные в объявлении.


Я закрою цитатой из Effective Java 2nd Edition , Item 41: Используйте разумную перегрузку :

Правила, определяющие, какая перегрузка выбрана, чрезвычайно сложны. Они занимают тридцать три страниц в спецификации языка, и лишь немногие программисты понимают все их тонкости.

Излишне говорить, что эта книга также настоятельно рекомендуется .

Смотри также


При явном приведении

Так как я могу вызвать перегрузку Object с аргументом null?

Простой: приведите null к Object. Существует несколько сценариев, в которых это полезно / необходимо, и это один из них.

Что если у меня перегрузка, скажем, Integer?

Тогда вызывается метод неоднозначный , и возникает ошибка времени компиляции.

JLS 15.12.2.5 Выбор наиболее специфического метода

Возможно, что ни один из методов не является наиболее специфичным, поскольку существует два или более методов, которые являются максимально специфичными. В этом случае [... с некоторыми исключениями] мы говорим, что вызов метода неоднозначный , и возникает ошибка времени компиляции.

Чтобы устранить неоднозначность, снова вы можете привести null (или другое выражение) к желаемому типу перегрузки.

Смотри также

5 голосов
/ 14 июня 2010

Компилятор всегда найдет самое узкое совпадение при разрешении перегруженных вызовов методов.

Кстати, соглашение Java состоит в том, чтобы использовать имена классов в верхнем регистре, то есть Another.

1 голос
/ 14 июня 2010

Я вполне уверен, что с Java 6 (я думаю, что Java 5 вызвала бы ошибку компилятора) в подобном случае, он выберет класс самого низкого уровня для атрибута null.(поскольку String является объектом, он находится ниже в иерархии)

...