强烈推荐阅读:
为什么需要泛型?
如一个问题: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) **)
测试类GoodsSeller,注意其 sellGoods(List <? extends Goods> goods) 的写法:
( 注:(1) sellGoods(List <? extends 接口> 接口的实现类对象): 即extends后面也可以跟一个接口的。
(2) sellGoods(List <? super Goods> goods):泛型参数可以是Goods或Goods的超类。)
以上写法是正确写法。
注:
(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的区别
自定义泛型类
可以发现形如:ArrayList<String> list = new ArrayList<String>();
或者ArrayList<Integer> list = new ArrayList<Integer>();
或者ArrayList<Cat> list = new ArrayList<Cat>();
ArrayList(这个类的功能就是存储数据)是一个类,这个类后面的<>中可以添加任意的类型;ArrayList就是一个泛型类,通过ArrayList的源码发现,在定义ArrayList类的时候,其参数使用了E,即并不确定该类到底存储什么样类型的数据,,用了E暂时占着这个坑,做一个虚假的代表,表示ArrayList可以存储E类型的数据或E的子类类型的数据。
通过ArrayList这个泛型类的定义,可以结合E这个占坑的魔法字符,构建自己的泛型类。
1.NumGeneric类使用了<T>这种形式,表示类中的T可以代表任意类型的数据,从而使得该类为泛型类。这个类中的public T num;中T到底是什么类型的数据暂不确定,等到具体使用的时候,给他赋什么类型的数据,这个类型的数据就会替换掉T这个占坑符。
自然,不同于ArrayList类,NumGeneric类的功能并不是存储数据,但该类广泛的数据类型也体现了泛型类的特点。
2.NumGenericTwo类,演示的是两个 <T,X>的形式。
注:
(1)具体为什么需要自定义泛型类,还不清楚,以前也没有遇到过,等得到具体业务场景使用时,可能会加深理解;
自定义泛型方法
自定义泛型方法:
(1)自定义泛型类:是类中的属性的类型可以为多种;
(2)自定义泛型方法,则是方法的参数类型可以为多种;
(3)泛型方法不一定写在泛型类里;
(4) 自定义泛型方法的实际应用常见还不清楚,知道定义形式后,以防以后遇到不认识;后续加深理解 。
运行结果:
注:
(1) 形如<T extends Number>指定一个参数类型的范围。
(2) 如上图,尚未执行程序就报错了,显示,自定义泛型方法如果采用<T extends Number>这样指定了类型的范围,如果不在这个范围内,在程序编译阶段就会报错。