extends
泛型中extends的主要作用是設(shè)定類型通配符的上限
要理解這句話叮盘,我們先從一個例子來看:
class Fruit{
public void call() {
System.out.println("這是一個水果");
}
}
class Banana extends Fruit{
@Override
public void call() {
System.out.println("這是一個香蕉");
}
}
class Apple extends Fruit{
@Override
public void call() {
System.out.println("這是一個蘋果");
}
}
public class Test{
public void test1(List<Fruit> fruits) {
for (Fruit fruit: fruits) {
fruit.call();
}
}
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
List<Fruit> fruits = apples; //類型轉(zhuǎn)換失敗
Test test = new Test();
test.test1(fruits); //失敗
}
}
我們使用Apple繼承了Fruit類别伏,然后建立了兩個list,一個容納的是apple,一個容納的是fruit诱担。按照常理來說,因為Apple繼承了Fruit电爹,List<Apple>應(yīng)該也是List<Fruit>的子類型蔫仙。但是實際上不是這樣的,運行上述程序丐箩,會報一個如下所示的錯誤摇邦。
Error:(42, 20) java: 不兼容的類型: java.util.List<com.company.Apple>無法轉(zhuǎn)換為java.util.List<com.company.Fruit>
我們可以這樣理解,如果上述代碼能夠正常運行屎勘,那把call方法修改成添加一個Banana對象會怎么樣施籍,因為test1方法中實際上使用的是List<Apple>,是不能夠添加到Banana的概漱,就會出錯丑慎。所以List<Apple>不是List<Fruit>的子類型。
那我們?nèi)绾翁幚眍愃频那闆r呢瓤摧,這就需要使用extends了竿裂。
public class Test{
public void test1(List<? extends Fruit> fruits) {
for (Fruit fruit: fruits) {
fruit.call();
}
}
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
Test test = new Test();
test.test1(apples);
}
}
<? extends Fruit>代表的是上界通配符,也就是說這個List中存放的對象都是Fruit以及其子類的對象照弥,這樣我們就不用因為輸入的List中類型的不同而改變代碼了腻异。
上界通配符有一個特點,就是程序只知道List<? extends Fruit>中的對象是Fruit的子類的對象这揣,但是如果Fruit的子類有很多個捂掰,那個在使用add方法的時候,就可能出現(xiàn)本來是List<Apple>曾沈,然后在其中添加了banana對象这嚣,從而失敗。
super
super與extends是完全相反的塞俱,其定義的是下界通配符姐帚。
List<? super Fruit>也就是說List中存放的都是Fruit和它的父類的對象,比如food障涯,Object罐旗。而且如果要在這個List中取出數(shù)據(jù)膳汪,那就不能夠確定具體是Fruit的哪個父類的對象,可能是Food九秀,可能是Object遗嗽。為了保證一定能夠取出來,就必須把其轉(zhuǎn)型成Object對象鼓蜒,但是這個時候就會失去原有對象的類型信息痹换。所以List<? super Fruit>不能夠提取數(shù)據(jù)。