2012-12-26 78 views
4

在下面的代碼片段中,有一個名爲show()的方法的三個版本。Java中方法的重載

package overloading; 

import java.util.ArrayList; 
import java.util.List; 

public final class Main 
{ 
    private void show(Object object) 
    { 
     System.out.println("Object"); 
    } 

    private void show(List<Object> list) //Unused method 
    { 
     System.out.println("List"); 
    } 

    private void show(Object[] objects) 
    { 
     System.out.println("Objects"); 
    } 

    private void addToList() 
    { 
     List<String>list=new ArrayList<String>(); 
     list.add("String1"); 
     list.add("String2"); 
     list.add("String3"); 
     show(list); // Invokes the first version 

     String []s={"111", "222", "333"}; 
     show(s); // Invokes the last version 
    } 

    public static void main(String[] args) 
    { 
     new Main().addToList(); 
    } 
} 

在這種最簡單的Java代碼,該方法調用show(s);(在addToList()方法的最後一行)調用最後一個版本的重載方法。它提供了一系列字符串 - String[],它被Object[]類型的接收參數接受。

然而,該函數調用show(list);嘗試調用重載方法的第一個版本的。它傳遞一個類型字符串列表 - List<String>這應該被中間版本接受,其中接收參數的類型爲List<Object>這些方法的中間版本完全沒有使用。如果第一個版本被刪除,這是一個編譯時錯誤。

爲什麼這個電話show(list);調用此版本 - private void show(List<Object> list){} - 中間的一個?

+0

+1。有趣。顯然,編譯器會考慮泛型類型註釋,並消除本來會選擇的重載方法。我會期望編譯錯誤,因爲泛型類型不匹配。如果你從'list'中刪除類型註釋(使它成爲'List list'),那麼中間方法就會被選中(當然會有警告和運行時錯誤)。 – Thilo

+1

當帶有'list'的泛型類型參數被刪除時選擇中間版本。 – Tiny

+0

從Java 5開始,隨着自動裝箱,可變參數和泛型的使用,方法調度變得非常複雜。這使得考試問題變得很好(或者至少是棘手)。 – Thilo

回答

7

總之,List<Object>不是List<String>

「修理」你的代碼,使用下面的代碼

private void show(List<? extends Object> list) 
{ 
    System.out.println("List"); 
} 

與數組不同(這是Java協變的),泛型類型的不同實例並不互相兼容,甚至沒有明確。

隨着聲明Generic<Supertype> superGeneric; Generic<Subtype> subGeneric; 編譯器會報告鑄件(Generic<Subtype>)superGeneric(Generic<Supertype>)subGeneric的轉換錯誤。

這種不相容性可通過本通配符被軟化如果?被用作實際類型參數:Generic<?>是用於這種類型的所有實例的抽象超類型。

see

4

List<Object>不是java中的超類List<String>。你所假設的是,Java在泛型上有協變性,它沒有。

這意味着,如果AB一個超類,List<A>不是List<B>

一個超類類似的問題是面臨Cannot convert generic to expanded nested type,你可以看看是否有任何變通的還有你的作品。

也許改變

private void show(List<Object> list) 

private void show(List<? extends Object> list) 

工作會如你所願?

+0

@Thilo爲什麼會出現錯誤?如果'show(Object object)'版本不存在,可能會有錯誤。 –

+0

我不希望'List '被編譯器丟棄爲最佳選擇。我本來預計它仍然會派遣(但後來抱怨不匹配)。這對我來說似乎是更可預測的行爲。我不希望泛型影響選擇哪種方法。但似乎我錯了。隨着自動裝箱,可變參數和泛型,自Java 5以來,方法調度已經變得非常複雜。這使得考試題目變得很好(或者至少是棘手)。 – Thilo

+0

@Thilo這就是失敗的原因,如果'list'是'List ',它會被選中,但是因爲它與列表不相關,所以失敗。如果像Scala那樣支持java協變性,它就會起作用。 –

3

我會說這是因爲參數不同,List <Object>不同於List <String> 因此,當您調用重載方法時,它將默認爲第一個只接受Object。

下面是一個簡單的例子:

public class Test 
{ 
    public static void overload (Object o) 
    { 
    System.out.println ("Object"); 

    } 

    public static void overload (List <Object> o) 
    { 
    System.out.println ("List Object"); 
    } 

    public static void main (String [] args) 
    { 
    overload (new ArrayList <Object>()); //"List Object" 
    overload (new ArrayList <String>()); //"Object" 

    } 
} 

參數化泛型列表,一切都應該工作。