Przeciążanie metod dla argumentu o wartości null


138

Dodałem trzy metody z parametrami:

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");
}

Kiedy dzwonię doSomething(null), kompilator zgłasza błąd jako niejednoznaczne metody . Więc jest problem, ponieważ Integeri char[]metody lub Integeri Objectmetody?


3
Wystarczy zmienić Integersię int.
Mudassir

2
@Mudassir: i co dokładnie by to rozwiązało?
Joachim Sauer

2
@Joachim Sauer: Jeśli zmieniono z Integer na int, to null nie jest odnoszone do typów pierwotnych w Javie, więc kompilator nie zgłosi błędu.
Phani

@Joachim Sauer: To nie zgłosi reference to doSomething is ambiguousbłędu.
Mudassir

Odpowiedzi:


220

Java zawsze będzie próbowała użyć najbardziej konkretnej odpowiedniej wersji dostępnej metody (patrz JLS §15.12.2 ).

Object, char[]I Integerwszystko może wziąć nulljako ważnej wartości. Dlatego wszystkie 3 wersje mają zastosowanie, więc Java będzie musiała znaleźć najbardziej szczegółową.

Ponieważ Objectjest to nadtyp char[], wersja tablicowa jest bardziej szczegółowa niż Object-wersja. Jeśli więc istnieją tylko te dwie metody, char[]zostanie wybrana wersja.

Gdy dostępne są obie wersje char[]i Integer, obie są bardziej szczegółowe, Objectale żadna nie jest bardziej szczegółowa niż druga, więc Java nie może zdecydować, którą z nich wywołać. W takim przypadku musisz wyraźnie wspomnieć, który z nich chcesz wywołać, rzutując argument na odpowiedni typ.

Należy zauważyć, że w praktyce problem ten występuje znacznie rzadziej, niż mogłoby się wydawać. Powodem tego jest to, że dzieje się tak tylko wtedy, gdy jawnie wywołujesz metodę z nulllub ze zmienną raczej niespecyficznego typu (na przykład Object).

Wręcz przeciwnie, następujące wezwanie byłoby całkowicie jednoznaczne:

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

Chociaż nadal przekazujesz wartość null, Java dokładnie wie, którą metodę wywołać, ponieważ weźmie pod uwagę typ zmiennej.


1
Dotyczy to języka Java 7. Czy dotyczy to również poprzednich wersji oprogramowania Java? Mam na myśli: jeśli masz kilka sygnatur metod z parametrami tylko wzdłuż hierarchii typów, to jesteś po stronie zapisu z wartością zerową jako rzeczywistą? A jeśli zbudowałeś „hierarchię dla”, tak jak w tym przykładzie, to tak nie jest?
Christian Gosch,

3
Jestem prawie pewien, że te zasady są takie same przynajmniej dla wszystkiego, co zaczęło się od Java 1.1 (z wyjątkiem oczywiście dodawania generyków).
Joachim Sauer

Czy to oznacza, że ​​jeśli kompilator miałby wybierać pomiędzy doSomething (String str) i doSomething (Object obj) podczas działania z doSomething (null), zostanie wywołana funkcja doSomething (String str).
Sameer

43

Każda para tych trzech metod jest sama w sobie niejednoznaczna, gdy jest wywoływana z nullargumentem. Ponieważ każdy typ parametru jest typem referencyjnym.

Poniżej przedstawiono trzy sposoby wywołania jednej określonej metody z wartością null.

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

Czy mogę zasugerować usunięcie tej niejednoznaczności, jeśli faktycznie planujesz wywoływać te metody z nullargumentami. Taki projekt zachęca do błędów w przyszłości.


1
Tylko Integer- char[]para jest niejednoznaczna, ponieważ w pozostałych dwóch przypadkach kompilator Java może wybrać najbardziej konkretny wybór, jak opisano w @JoachimSauer.
kajacx

1
@kajacx: ​​oryginalne pytanie OP dotyczyło wywoływania tych metod z nullparametrem as. Pod tym warunkiem wszystkie trzy pary są niejednoznaczne. W ogólnym przypadku zgadzam się, że tylko Integer - char[]para jest niejednoznaczna.
jmg

co powiesz doSomething(null)na public static void doSomething(String str) { System.out.println("String called"); } To zwróci ciąg o nazwie.
Sameer

Czy można użyć anotacji, takiej jak „dopuszcza wartość null” lub „nie dopuszcza wartości null” i ustawić deklaracje tak, aby tylko jedna metoda, za pomocą której chcesz uzyskać wartość null, aby jawny argument „null” (ale niejawny typ zerowy) zawsze wybierał jednoznacznie określone przeciążenie?
peterk

5

nulljest prawidłową wartością dla dowolnego z trzech typów; więc kompilator nie może zdecydować, której funkcji użyć. Użyj czegoś takiego jak doSomething((Object)null)lub doSomething((Integer)null)zamiast.


Usunąłem metodę z parametrem Integer, wywołuje funkcję i zwraca dane wyjściowe jako „Array Called” , więc jaki jest kontrakt między Array i Object ?
Phani

3
Tablice Java są również obiektami.
Zds

2

Każda klasa w Javie rozszerza klasę Object, nawet klasa Integer rozszerza również Object. Dlatego zarówno Object, jak i Integer są uważane za instancję Object. Więc kiedy jako parametr przekażesz null, kompilator nie będzie wiedział, którą metodę obiektu wywołać, tj. Z parametrem Obiekt lub parametr Integer, ponieważ oba są obiektami, a ich odniesienie może mieć wartość null. Ale prymitywy w Javie nie rozszerzają Object.


1

Próbowałem tego i kiedy istnieje dokładnie jedna para przeciążonych metod, a jedna z nich ma parametr typu Object, wówczas kompilator zawsze wybierze metodę z bardziej konkretnym typem. Ale jeśli istnieje więcej niż jeden określony typ, kompilator zgłasza niejednoznaczny błąd metody.

Ponieważ jest to zdarzenie czasu kompilacji, może się to zdarzyć tylko wtedy, gdy celowo przekaże wartość null do tej metody. Jeśli jest to zrobione celowo, lepiej jest ponownie przeciążać tę metodę bez parametrów lub w ogóle utworzyć inną metodę.


0

występuje niejednoznaczność z powodu funkcji doSomething (char [] obj) i doSomething (Integer obj).

char [] i Integer są takie same nadrzędne dla null, dlatego są niejednoznaczne.


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);
    }
}

Wynik to Int o nazwie null, a więc niejednoznaczność występuje w przypadku char [] i Integer

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.