Перегрузка метода для нулевого аргумента


133

Я добавил три метода с параметрами:

public static  void doSomething(Object obj) {
    System.out.println("Object called");
}

public static  void doSomething(char[] obj) {
    System.out.println("Array called");
}

public static  void doSomething(Integer obj) {
    System.out.println("Integer called");
}

Когда я звоню doSomething(null), компилятор выдает ошибку как неоднозначные методы . Так это проблема , потому что Integerи char[]методы или Integerи Objectметоды?


3
Просто измените Integerк int.
Mudassir 08

2
@Mudassir: и что именно это решит?
Joachim Sauer

2
@Joachim Sauer: При изменении с Integer на int null не относится к примитивным типам в Java, поэтому компилятор не выдаст ошибку.
Phani 08

@Joachim Sauer: Это не приведет к reference to doSomething is ambiguousошибке.
Mudassir 08

Ответы:


211

Java всегда будет пытаться использовать наиболее конкретную применимую версию доступного метода (см. JLS §15.12.2 ).

Object, char[]и Integerвсе они могут nullбыть допустимы. Следовательно, применимы все 3 версии, поэтому Java должна будет найти наиболее конкретную.

Поскольку Objectэто супер-тип char[], версия массива более конкретна, чем Object-version. Поэтому, если существуют только эти два метода, char[]будет выбрана версия.

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

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

Напротив, следующий вызов был бы совершенно однозначным:

char[] x = null;
doSomething(x);

Хотя вы по-прежнему передаете значение null, Java точно знает, какой метод вызывать, поскольку он будет учитывать тип переменной.


1
Это заявлено для Java 7. Применимо ли это также к предыдущим версиям Java? Я имею в виду: если у вас есть несколько сигнатур методов с параметрами только в иерархии типов, то вы находитесь на стороне сохранения с нулевым фактическим значением? А если вы построили «иерархию для», как в примере здесь, то нет?
Кристиан Гош,

2
Я почти уверен, что эти правила одинаковы, по крайней мере, для всего, начиная с Java 1.1 (за исключением добавления универсальных шаблонов, очевидно).
Иоахим Зауэр,

Означает ли это, что, если бы компилятор выбирал между doSomething (String str) и doSomething (Object obj) во время выполнения с doSomething (null), будет вызываться doSomething (String str).
Самир

43

Каждая пара из этих трех методов сама по себе неоднозначна при вызове с nullаргументом. Поскольку каждый тип параметра является ссылочным типом.

Ниже приведены три способа вызвать один ваш конкретный метод с помощью null.

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

Могу я предложить устранить эту двусмысленность, если вы действительно планируете вызывать эти методы с nullаргументами. Такой дизайн предполагает ошибки в будущем.


1
Только Integer- char[]пара неоднозначна, так как в двух других случаях, Java компилятор может выбрать наиболее выбор конкретного, как описано @JoachimSauer.
kajacx

1
@kajacx: ​​исходный вопрос OP был о вызове этих методов с nullпараметром as. При этом предварительном условии все три пары неоднозначны. В общем случае согласен, что только Integer - char[]пара неоднозначна.
jmg

что о doSomething(null)для public static void doSomething(String str) { System.out.println("String called"); } Вернет строку с именем.
Самир

Можно ли использовать аннотацию, такую ​​как «допускающий значение NULL» или «не допускающий значение NULL», и настроить объявления так, чтобы только один метод, с которым вы хотите получить значение NULL, чтобы явный аргумент «null» (но неявный нулевой тип) всегда однозначно выбирал конкретная перегрузка ??
peterk

4

nullявляется допустимым значением для любого из трех типов; поэтому компилятор не может решить, какую функцию использовать. Используйте что-нибудь вроде doSomething((Object)null)или doSomething((Integer)null)вместо.


Я удалил метод с параметром Integer, он вызывает функцию и возвращает вывод как «Array Called» , так что в чем заключается контракт между Array и Object ?
Phani 08

2
Массивы Java также являются объектами.
Zds 08

2

Каждый класс в Java расширяет класс Object, даже класс Integer также расширяет Object. Следовательно, как объект, так и целое число считаются экземпляром объекта. Поэтому, когда вы передаете null в качестве параметра, компилятор не понимает, какой метод объекта вызывать, т.е. с параметром Object или параметром Integer, поскольку они оба являются объектами, и их ссылка может быть нулевой. Но примитивы в java не расширяют Object.


1

Я пробовал это, и когда есть ровно одна пара перегруженных методов, и один из них имеет тип параметра Object, тогда компилятор всегда будет выбирать метод с более конкретным типом. Но когда существует более одного конкретного типа, компилятор выдает ошибку неоднозначного метода.

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


0

существует двусмысленность из-за doSomething (char [] obj) и doSomething (Integer obj).

char [] и Integer одинаково превосходят null, поэтому они неоднозначны.


0
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

Результат - Int, называемый null, поэтому двусмысленность возникает с char [] и Integer.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.