Метод Перевантаження для нульового аргументу


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.
Мудассір

2
@Mudassir: а що саме це вирішило б?
Йоахім Зауер

2
@Joachim Sauer: Якщо змінено з Integer на int, то null не посилається на примітивні типи на Java, тому компілятор не видасть помилки.
Фані

@Joachim Sauer: Це не призведе до reference to doSomething is ambiguousпомилки.
Мудасір

Відповіді:


211

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

Object, char[]і Integerвсі вони можуть приймати nullяк дійсне значення. Тому всі 3 версії застосовні, тому Java доведеться знайти найбільш конкретну.

Оскільки Objectце супер-тип char[], версія масиву є більш специфічною, ніж Object-версія. Тож якщо існують лише ці два методи, char[]буде обрана версія.

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

Зауважте, що на практиці ця проблема виникає набагато рідше, ніж можна було б подумати. Причиною цього є те, що це відбувається лише тоді, коли ви явно викликаєте метод із nullзмінною досить неспецифічного типу (наприклад, Object).

Навпаки, таке виклик було б абсолютно однозначним:

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

Хоча ви все ще передаєте значення null, Java точно знає, який метод викликати, оскільки він враховує тип змінної.


1
Це зазначено для Java 7. Чи це стосується і попередніх версій Java? Я маю на увазі: Якщо у вас є кілька підписів методу з параметрами тільки уздовж ієрархії типу, то ви знаходитесь на стороні збереження з null як фактичне значення? І якщо ви побудували "ієрархію для", як у прикладі тут, то це не так?
Крістіан Гош

2
Я майже впевнений, що ці правила однакові принаймні для всього, починаючи з Java 1.1 (окрім додавання загальних даних, очевидно).
Йоахім Зауер

Чи означає це, що якщо компілятор повинен був вибирати між doSomething (String str) і doSomething (Object obj) під час виконання з doSomething (null), буде викликано doSomething (String str).
Самєр

43

Кожна пара цих трьох методів неоднозначна сама по собі, коли викликається nullаргументом. Оскільки кожен тип параметра є еталонним типом.

Нижче наведено три способи викликати нульовий один конкретний метод.

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

Я можу запропонувати усунути цю неоднозначність, якщо ви дійсно плануєте викликати ці методи nullаргументами. Така конструкція запрошує помилки в майбутньому.


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

1
@kajacx: ​​Оригінальне питання ОП стосувалося виклику цих методів nullяк параметра. За цією передумовою всі три пари неоднозначні. У загальному випадку я погоджуюся, що лише Integer - char[]пара неоднозначна.
jmg

про що doSomething(null)для public static void doSomething(String str) { System.out.println("String called"); } цього повернеться рядок з назвою.
Самєр

Чи можливо використовувати анотацію типу "nullable" або "not nullable" і налаштувати декларації, так що лише один метод, з якого ви хочете отримати null, таким чином, щоб явний "null" (але неявний тип null) завжди однозначно вибирав специфічне перевантаження ??
peterk

4

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


Я видалив метод із параметром Integer, він викликає функцію та повертає вихідний сигнал як "Array Called" , тож який контракт між Array та Object ?
Фані

2
Масиви Java також є Об'єктами.
Зд

2

Кожен клас на Java розширює клас Object.Even Integer class також розширює Object. Отже, і Object, і Integer вважаються екземпляром Object. Отже, коли ви передаєте null як параметр, ніж компілятор заплутається, який метод об'єкта викликати, тобто з параметром Object або параметром Integer, оскільки вони обидва є об'єктом, і їх посилання може бути нульовим. Але примітиви в Java не поширюють Об'єкт.


1

Я спробував це, і коли є одна пара перевантаженого методу, і один з них має тип параметра Object, тоді компілятор завжди вибере метод із більш конкретним типом. Але коли існує більше одного конкретного типу, тоді компілятор видає неоднозначну помилку методу.

Оскільки це подія часу компіляції, це може статися лише тоді, коли навмисно передається нуль цьому методу. Якщо це зроблено навмисно, то краще перевантажити цей метод знову без параметрів або взагалі створити інший метод.


0

існує неоднозначність через doSomething (char [] obj) і doSomething (Integer obj).

char [] і Integer однаково покращені за нульовими показниками, тому вони неоднозначні.


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 називаються нульовими, тому неоднозначність має char [] та Integer

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.