2015-06-27 34 views
1

我想明白下面的代碼片段,搜索與問候計算器鏈接lowerboundupperbound下界通配符

只是想獲得在以下行的混亂,

SI = S //確定爲什麼?對象數組可以隱含地轉換爲整數數組?

List<? extends Number> l = new ArrayList<>(); 
List<? extends Integer> i = new ArrayList<>(); 
l = i;//OK i is a subtype of l 

List<? super Number> s = new ArrayList<>(); 
List<? super Integer> si = new ArrayList<>(); 

si = new ArrayList<Integer>();//OK understand integer matches the pattern of ? super Integer 
s = new ArrayList<Object>();//OK understand that object is superclass of Number 

si=s//OK why? arrays of objects can be implicitly casted to arrays of integers? 

//consider this 
List<Integer> integers = new ArrayList<Integer>(); 
List<Object> objects = new ArrayList<Object>(); 
integers = objects; //NOT OK Type mismatch: cannot convert from List<Object> to List<Integer> 

//consider this 
Integer ten = 10; //integer ten 
Object none = new Object();//some none 
ten = none;//NOT OK none cannot be implicitly casted to ten 

任何幫助表示讚賞

回答

2

記住gnerics是編譯器不運行時信息的好處。

當你做si = s你正在分配一個列表的東西,是一個超類的數量的變量,可以引用一個Integer的超類東西的列表。

如果它是一個數字列表,它仍然是一個Integer超類的東西的列表。

我們知道它實際上是一個Object的Arraylist,因爲您之前已經指定了它。

我們也知道Object的ArrayList擴展了Object的List。

Object的列表是一個列表,它是Number的超類,這是之前賦值工作的原因。

我們也知道List對象是Integer超類的東西的列表,但它與編譯器無關,只關心Number的任何超類也是Integer的超類。

+0

只是爲了讓編譯器正確解析wrt泛型,如果我說{si超級整數} = {s數組超級數組}編譯器不關心右側(超級數字)類型參數是否可以投射到左側(整數超級)....它只關心左類型參數是右類型參數的後代/子類型還是隻關心右類型參數是左類型參數的超類型/祖先? – chebus

+0

編譯器不在乎,但Number的任何超級都是Integer的超級,因爲Number是Integer的超級。另外要注意將數組與數組等同爲數組列表是有趣的對象,它們是基本類型和類別的類別,並且整數數組可以被分配給數組數組,但是整數列表不能被分配給數字列表,因爲通用系統不允許它.. – redge

+0

我明白,Number是整數的超類。假設這種情況, 列表 lst = new ArrayList <>(); lst.add({A或A的子類的實例,它可以是A1,A2等任何東西。 假設我已經添加了s.add(A2); 現在, 列表 sl = new ArrayList <>(); sl.add({A1的實例或A1的子類)}) 假設我添加了sl.add(A1); 假定lst = sl; //這意味着我只能添加A1或A1的子類,所有這些子類都繼承A。 因此,我們說A1的子類列表(從A繼承)可以安全地分配給A的子列表? – chebus

1

我不知道你在爲什麼要使用<? super Number>代替<? extends Number>清楚......

聲明與<? extends Number>擔保任何一種類型,採用這種類型,這將至少榮譽合同一個Number。但是給出這種類型列表的一段代碼不能將新成員添加到列表中。考慮以下代碼:

void appendInteger (List <? extends Number> list) { 
    list.add (new Integer (3)); // Compiler error on this line 
} 

您可以用appendInteger (new ArrayList <Double>());現在把這塊,無論是DoubleInteger延長Number,因此參數將被編譯所接受。但是你可以看到,如果允許追加,則違反了調用代碼中聲明的合同。出於這個原因,編譯器將不允許添加或替換用<? extends T>聲明的任何結構中的成員的任何代碼。上述方法會導致編譯器錯誤。

簡而言之,通過上界通配符類型,您可以讀取項目,但不會將成員放置到結構中。

相反,使用List <? super Number>意味着列表中的對象不是的而不是Number。考慮這種方法:

void getInteger (java.util.List <? extends Number> list) { 
    Number n = list.get (0); // Compiler error on this line 
} 

代碼不知道list中元素的類型是什麼。所以編譯器也會用這個方法嘔吐。您可以使用繼承路徑爲Number的任何類型的對象來添加或替換list中的成員。但閱讀列表的成員,你必須把他們當作Object類型或使用類型轉換:

Object v = list.get (0); // this will work 
Number n = (Number) list.get (0); // this will also work 

考慮到這方面的知識,在參與si = s對象再看看。請記住,您無法讀取這些結構中的項目,只能添加或替換成員。您可以在s中放置的任何對象也可以在si中使用。因此,將s分配給si是可以接受的。

+0

謝謝! **但是,您只能將列表中的成員讀入Object類型的變量,除非您使用類型轉換。** 如果您在討論超級(下限),當您閱讀成員時,我不認爲這是真實的列表到它可以分配給Object的變量(至少),但是它不能被分配給Number(或特定的下限類型參數)。 Object obj = s.get(0); //正常工作 這也不是真的**簡而言之,對於下界通配符類型,您可以讀取項目但不將成員放置到結構中** 它應該是上限,可以讀取而不添加 – chebus

+0

謝謝。作爲迴應編輯。 –