java泛型中的上界下界(上限下限) (轉)

java泛型中的super關鍵字不太常用,也不太好理解,今天又從頭看了看java的泛型機制,作一記錄。
上界:
上界用extends關鍵字聲明,表示參數化的類型可能是所指定的類型,或者是此類型的子類。如下面的代碼:

Java代碼
1.public void upperBound(List<? extends Date> list, Date date)
2.{
3. Date now = list.get(0);
4. System.out.println("now==>" + now);
5. //list.add(date); //這句話無法編譯
6. list.add(null);//這句可以編譯,因爲null沒有類型信息
7.}
public void upperBound(List<? extends Date> list, Date date)
{
Date now = list.get(0);
System.out.println("now==>" + now);
//list.add(date); //這句話無法編譯
list.add(null);//這句可以編譯,因爲null沒有類型信息
}

爲什麼會無法編譯呢,實際調用時傳入的list可能是java.util.Date的某個子類的參數化類型,如:

Java代碼
1.public void testUpperBound()
2.{
3. List<Timestamp> list = new ArrayList<Timestamp>();
4. Date date = new Date();
5. upperBound(list,date);
6.}
public void testUpperBound()
{
List<Timestamp> list = new ArrayList<Timestamp>();
Date date = new Date();
upperBound(list,date);
}

也就是說,現在upperBound方法中實際的list是List<Timestamp>,向它添加一個Date類型,肯定是不行的。相反,讀取數據時,不管實際的list是什麼類型,但可以知道它至少會返回一個Date類型,所以用foreach,get等沒有問題。

那麼如何解決呢,可以使用泛型方法

Java代碼
1.public <T extends Date> void upperBound2(List<T> list, T date)
2.{
3. list.add(date);
4.}
public <T extends Date> void upperBound2(List<T> list, T date)
{
list.add(date);
}

這裏方法聲明中的T作爲一種參數化信息,會存儲在java字節碼中,T的實際類型由調用時的參數決定的。比如:

Java代碼
1.public void testUpperBound2()
2.{
3. List<Timestamp> list = new ArrayList<Timestamp>();
4. Date date = new Date();
5. Timestamp time = new Timestamp(date.getTime());
6. upperBound2(list,time);
7. //upperBound2(list,date);//這句同樣無法編譯
8.}
public void testUpperBound2()
{
List<Timestamp> list = new ArrayList<Timestamp>();
Date date = new Date();
Timestamp time = new Timestamp(date.getTime());
upperBound2(list,time);
//upperBound2(list,date);//這句同樣無法編譯
}

上面代碼中的list的類型參數決定了方法中T的類型,所以會看到註釋掉的內容不能編譯。而換成這樣:
List<Date> list2 = new ArrayList<Date>();
upperBound2(list2,date);
編譯就沒有任何問題了。


下界
下界用super進行聲明,表示參數化的類型可能是所指定的類型,或者是此類型的父類型,直至Object。如下面的代碼:

Java代碼
1.public void lowerBound(List<? super Timestamp> list)
2.{
3. Timestamp now = new Timestamp(System.currentTimeMillis());
4. list.add(now);
5. //Timestamp time = list.get(0); //不能編譯
6.}
public void lowerBound(List<? super Timestamp> list)
{
Timestamp now = new Timestamp(System.currentTimeMillis());
list.add(now);
//Timestamp time = list.get(0); //不能編譯
}

這又爲什麼不能通過編譯呢,看看調用代碼:

Java代碼
1.public void testLowerBound()
2.{
3. List<Date> list = new ArrayList<Date>();
4. list.add(new Date());
5. lowerBound(list);
6.}
public void testLowerBound()
{
List<Date> list = new ArrayList<Date>();
list.add(new Date());
lowerBound(list);
}

lowerBound方法中的List<? super Timestamp>表示這個list的參數類型可能是Timestamp或Timestamp的父類,如後面測試代碼裏,實際傳入的是一個List<Date>類型。向List<Date>中add一個Timestamp肯定是沒有問題的,但list.get()方法返回的對象類型可能是Date甚至是Object,你不能說list.get(0)返回的就是一個Timestamp,這裏是向下類型轉換了,編譯器無法處理,所以這裏不能編譯。用java泛型實現的擦拭法解釋,編譯後會是如下的僞代碼:

Java代碼
1.public void lowerBound(List list)
2.{
3. Timestamp now = new Timestamp(System.currentTimeMillis());
4. list.add(now);
5. Timestamp time = (Timestamp)list.get(0); //①
6.}
7.public void testLowerBound()
8.{
9. List list = new ArrayList();
10. list.add(new Date());
11. lowerBound(list);
12.}
public void lowerBound(List list)
{
Timestamp now = new Timestamp(System.currentTimeMillis());
list.add(now);
Timestamp time = (Timestamp)list.get(0); //①
}
public void testLowerBound()
{
List list = new ArrayList();
list.add(new Date());
lowerBound(list);
}

代碼①進行了強制類型轉換,但實際添加進去的是一個Date類型,肯定會報ClassCastException,編譯器無法保證向下類型轉換的安全,所以這一句自然就無法編譯了。


[url]http://fyting.iteye.com/blog/122732[/url]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章