2011-08-14 4 views
5

Podczas przeciążania metod, które zawierają parametry, które nie pasują, JVM będzie zawsze używać metody z najmniejszym argumentem, który jest szerszy niż parametr.Metody przeciążania za pomocą var-args - w połączeniu z boksem i poszerzaniem

I potwierdziły wyżej z dwoma następującymi przykładami:

Rozszerzenie: Bajt rozszerzony int

class ScjpTest{ 

    static void go(int x){System.out.println("In Int");} 
    static void go(long x){System.out.println("In long");} 

    public static void main (String[] args){ 

     byte b = 5; 

     go(b); 

    } 

}

Boks: int zapakowane Integer

class ScjpTest{ 

    static void go(Integer x){System.out.println("In Int");} 
    static void go(Long x){System.out.println("In Long");} 

    public static void main (String[] args){ 

     int b = 5; 

     go(b); 

    } 

} 

Oba powyższe przykłady wyświetlają "In Int", co jest poprawne. Jestem zdezorientowany, choć gdy sytuacja wiąże VAR args, jak pokazano w poniższym przykładzie

class ScjpTest{ 

    static void go(int... x){System.out.println("In Int");} 
    static void go(long... x){System.out.println("In lInt");} 

    public static void main (String[] args){ 

     byte b = 5; //or even with: int b = 5 

     go(b); 

    } 

} 

Powyższy produkuje następujący błąd:

ScjpTest.java:14: reference to go is ambiguous, both method go(int...) in ScjpTest and method go(long...) in ScjpTest match 
       go(b); 
       ^
1 error 

Dlaczego nie ona stosować te same reguły jak w poprzednim przykłady? tj. poszerzyć bajt do int, ponieważ jest najmniejszy, który jest większy niż bajt?

+0

On Java 7, twój ostatni przykład działa dobrze. – toto2

Odpowiedz

5

składnia var-args jest tylko alias do przechodzenia tablicę jako argument:

foo(int ... arg) jest równa foo(int[] arg)

Ale tablice nie są hierarchiczne. String[] nie jest podklasą Object[]. Dokładnie ta sama reguła jest istotna dla argumentów metody. Dlatego kompilator nie może rozróżnić dwóch przeciążonych metod, które akceptują long[] i int[] podczas przekazywania byte.

+0

Źle. String [] jest podklasą Object []. Tablice są kowariancyjne w Javie (ale nie generyczne).Zobacz moją odpowiedź: w rzeczywistości jest to błąd w starszych wersjach Javy, który nie działa. Przykład ziggy działa w Javie 7. – toto2

+0

... ale w rzeczywistości to, co jest w grze w tym przykładzie, nie jest dziedziczone, ale rozszerzające konwersje typów pierwotnych. – toto2

1

To faktycznie działa w Javie 7: zwraca "In Int" również dla przykładu varargs. Sądzę, że była to tylko brakująca funkcja w poprzednich wersjach. Nie wiem, jakiej wersji Java używasz, ale może działa również w Javie 6.

Muszę jednak powiedzieć, że byłem zaskoczony, że działa nawet twój pierwszy przykład (bez varargów). Nie wiedziałem o prymitywnych rozszerzeniach konwersji. Nawiasem mówiąc, twoje pierwsze i ostatnie przykłady zawodzą, jeśli zamiast tego używasz Bajtów, Integer i Długich, ponieważ nie istnieje żadna hierarchia między tymi typami (z wyjątkiem tego, że wszystkie są podklasami Numeru).

1

Jak zauważył AlexR, var-args jest jak tablica. Tablice prymitywów (takich jak byte[] short[] int[] long[] float[] double[] wydają się być wewnętrznie skompilowany do tej samej klasy Dlatego twoi przeciążone metody są niejednoznaczne Jednakże następujący kod jest całkowicie poprawny:..
static void go(int... x){System.out.println("In Int");}
static void go(Long... x){System.out.println("In lInt");}

To kompiluje pomyślnie (od int[] i Long[] różne rodzaje) i produkuje wyjście In Int.
Jeśli przygotowuje się do SCJP, gorąco polecam czytanie książki SCJP Sun Certified Programmer for Java 6 Exam 310-065. sekcja Przeciążenie w tej książce obejmuje wszystkie sztuczki z mieszaniem boks i vAR args.