为什么需要泛型?
如一个问题:Set set1 = new Set();定义了一个Cat类;向set1集合中添加cat对象;当遍历set1时候,需要用到Iterator迭代器;Iterator it = set1.iterator();其中需要用到的it.next()的方法的返回值是Object类型的,如果要调用Cat类中定义的方法就需要把返回值转型为Cat类型。但如果错误地写成:String c1 = (String)it.next();编译是不会报错的,只有在运行时才会报错。
可以发现,如果不使用泛型:集合中添加的是Object类的对象,就会(1)涉及强制类型转换;(2)可向集合中添加任意类型的对象,存在风险;
为了避免上述问题:需要在创建Set的时候就制定Set中存入对象的类型:Set<Cat> set1 = new Set<Cat>();
泛型的使用语法:
(1)如 List<String> list = new ArrayList<String>();
(2)Java SE7及以后的版本中,构造方法中可以省略泛型类型,即也可以写作: List<String> list = new ArrayList<>();
多态和泛型:
(1)错误示例:父类 Animal,子类Cat继承Animal类, List<Animal> list = new ArrayList<Cat>();这样写是错误的;即前后的类型必须要一致。
(2)List<Object> list = new ArrayList<String>();和 List<Number> numbers = new ArrayList<Integer>()也是错误的;前后的类型必须要一致,也就是变量声明的类型必须匹配传递给实际对象的类型。
疑问:List<Animal> list = new ArrayList<Animal>();如果Cat是Animal的子类,Cat类型的对象可不可以存入list? 实测发现是可以的,但好像不提倡这么做。
1.泛型作为方法参数
父类:Goods类;
子类:Book类、Clothes类、Shoes类;
工具类:GoodsSeller类;
测试类:GoodsTest;
(注:(1)这其中也涉及了多态的应用;(2)核心是sellGoods(List<? extends Goods> goods)。)
public abstract class Goods {
public abstract void sell();
}
public class Book extends Goods {
@Override
public void sell() {
// TODO Auto-generated method stub
System.out.println("Book类");
}
}
public class Clothes extends Goods {
@Override
public void sell() {
// TODO Auto-generated method stub
System.out.println("Clothes类");
}
}
public class Shoes extends Goods {
@Override
public void sell() {
// TODO Auto-generated method stub
System.out.println("Shoes类");
}
测试类GoodsSeller,注意其 sellGoods(List<? extends Goods> goods) 的写法:
( 注:(1)sellGoods(List<? extends 接口> 接口的实现类对象): 即extends后面也可以跟一个接口的。
(2)sellGoods(List<? super Goods> goods):泛型参数可以是Goods或Goods的超类。)
public class GoodsSeller {
public void sellGoods(List<? extends Goods> goods){
// 遍历Set集合
for(Goods g : goods){
g.sell();
}
}
}
public class GoodsTest {
public static void main(String[] args) {
List<Book> books = new ArrayList<Book>();
books.add(new Book());
books.add(new Book());
List<Clothes> clothes = new ArrayList<Clothes>();
clothes.add(new Clothes());
clothes.add(new Clothes());
List<Shoes> shoes = new ArrayList<Shoes>();
shoes.add(new Shoes());
shoes.add(new Shoes());
GoodsSeller goodsSeller = new GoodsSeller();
goodsSeller.sellGoods(books);
}
}
以上写法是正确写法。
注:
(1)如果GoodsSeller类里,sellGoods方法参数如下时:
测试类里的方法调用会出错:
出现了上面的错误,如果把List<Book> books = new ArrayList<Book>();改成List<Goods> books = new ArrayList<Goods>();。不会报错,而且会正常执行。
但是,如果这样,books集合中也可以添加Clothes和Shoes类型的对象了,失去了泛型本来的意义。
所以为了根本解决这个问题,在测试类里面改成如上所示的:sellGoods(List<? extends Goods> goods) 就能解决:
2.【泛型作为方法参数】和【方法重载】的关联
这儿到底想表达什么,至今还不明白,,,,,。这是自定义泛型方法。
(1)一个新的写法:public <T extendx Number> void peintValue(T t):该方法的参数类型不仅可以是Number类型的,也可以是Number的子类类型的。这就是泛型之所以为泛型的意义吗?后续,需要在实际应用中继续加深对泛型的理解。这种写法,应该是自定义泛型了,下篇博客会讲到
相较于涉及泛型的方法,和具体类型的方法,实际调用时候,还是会选择更亲近的那一个。
3.?和T的区别