泛型的继承和通配符
一:泛型的继承和通配符
(1)泛型不具备继承性,但是数据具备继承性
泛型不具备继承性:
public class Test7 {
public static void main(String[] args) {
// 泛型不具备继承性,但是数据具备继承性
// 创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
// 调用method方法
method(list1);
method(list2); // 编译报错
method(list3); // 编译报错
}
// 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
// 传递list2或者是list3都不行,只有你传list1才是可以的。因为list1集合里面装的是Ye,跟这里的形参是完全一致的。
// 这个就是泛型不具备继承性
public static void method(ArrayList<Ye> list) {
}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
数据具备继承性:
public class Test7 {
public static void main(String[] args) {
// 泛型不具备继承性,但是数据具备继承性
// 创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
// 但是数据具备继承性
// 我现在可以往集合里面添加,可以添加Ye的对象,还可以添加Fu的对象,还可以添加Zi的对象
// 这个就叫做数据具备继承性
list1.add(new Ye());
list1.add(new Fu());
list1.add(new Zi());
}
// 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
// 传递list2或者是list3都不行,只有你传list1才是可以的。因为list1集合里面装的是Ye,跟这里的形参是完全一致的。
// 这个就是泛型不具备继承性
public static void method(ArrayList<Ye> list) {
}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
需求:定义一个方法,形参是一个集合,但是集合中的数据类型不确定
public class Test8 {
public static void main(String[] args) {
// 需求:定义一个方法,形参是一个集合,但是集合中的数据类型不确定
// 创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
ArrayList<Student> list4 = new ArrayList<>();
method(list1);
method(list2);
method(list3);
method(list4);
}
// 既然这里的类型不确定,是不是可以用刚刚学的泛型方法去搞定?完全可以
// 这里定义一个泛型E,ArrayList里面就可以用上这个E了
// 此时创建三个集合的对象,再去调用method方法,可以把list1、list2、list3传递过去,传递过去都没问题
// 但是此时会有一个弊端:
// 利用泛型方法会有一个小弊端,此时它可以接收任意的数据类型,包括我们定义的Ye、Fu、Zi,甚至是你定义一个其他的例如Student类,
// 不在前面的继承结构当中,比如说一个Student,都是可以传递过去的。method(list4);没有报错,因为这里的method方法可以接受任意的数据类型
// 因为这里的E就是不确定的类型,随便传递一个过来都是可以的
// 但是在有的时候我们不希望是这样的,我们希望:本方法虽然不确定类型,但是以后我希望只能传递Ye Fu Zi,不希望能传递Student2
// 那该怎么办?
// 难不成直接在泛型里面写个Ye?public static void method(ArrayList<Ye> list) {},不可以!
// 因为刚刚才说过,泛型是不具备继承性的,所以和刚刚一样:传递Ye,和他一样是可以的,但是传递Fu和Zi的时候就不行了。
// 这个时候怎么解决?
// 此时我们就可以使用泛型的通配符,在java当中泛型的通配符就是一个 ? ,他也表示不确定的类型,也就是一切类型
// 但是他可以进行类型的限定,它的限定方式有两种:
// ? extends E: 表示可以传递E或者E所有的子类类型
// ? super E: 表示可以传递E或者E所有的父类类型
// 按照这样(public static void method(ArrayList<? extends Ye> list) {})写了过后:
// methods(list4)就会报错了,因为list4和集成结构没有关系
// 如果是(public static void method(ArrayList<? super Zi> list) {}),就表示现在传递的类型必须是Zi或者Zi的父类类型
// 应用场景:
// 1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口
// 2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以用泛型的通配符
// 泛型的通配符:
// 关键点:可以限定类型的范围
// 而且使用这个泛型通配符?的话,前面可以不用定义这个?哦
public static void method(ArrayList<? super Zi> list) {}
}
class Ye {}
class Fu extends Ye {}
class Zi extends Fu {}
class Student {}
泛型总结:
(1)什么是泛型?
JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
(2)泛型的好处?
1.统一数据类型
2.把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来
(3)泛型的细节?
1.泛型中不能写基本数据类型
2.指定泛型的具体类型后,传递数据时,可以传入该类型和他的子类类型
3.如果不写泛型,类型默认是Object
(4)哪里定义泛型?
1.泛型类:在类名后面定义泛型,创建该类对象的时候,确定类型
2.泛型方法:在修饰符后面定义方法,调用该方法的时候,确定类型
3.泛型接口:在接口名后面定义泛型,实现类确定类型,实现类延续泛型
(5)泛型的继承和通配符
1.泛型不具备继承性,但是数据具备继承性
2.泛型的通配符有:?
? extends E:E和E的子类
? super E:E和E的父类
(6)使用场景
1.定义类、方法、接口的时候,如果类型不确定,就可以定义泛型
2.如果类型不确定,但是能知道是哪个继承体系中的,可以使用泛型的通配符