前言
如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型,此时可以往集合添加任意的数据类型。这带来了一个坏处就是我们在获取数据的时候,无法使用他的特有行为。
此时推出了泛型,可以再添加数据的时候就把类型进行统一,而且我们在获取数据的时候,也省的强转了,非常的方便。
一、泛型概述
泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
泛型的格式<数据类型>
注意:泛型只能支持引用数据类型
Java中的泛型是伪泛型,java文件中有泛型但是转为class文件之后泛型会消失,记作泛型的擦除
ArrayList<String> list= new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
二、泛型的好处
泛型的好处:
- 统一数据类型
- 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
三、 泛型的细节
- 泛型中不能写基本数据类型,基本数据类型需要其包装类如int的Integer
- 指定泛型的具体数据类型后,传递数据时,可以传入该类类型或者其子类类型
- 如果不写泛型,类型默认是Object
四、 泛型的定义
4.1 泛型类
使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
public class MyArrayList<E> {
}
此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T、E、K、V等,创建该类对象时,E就确定了类型。
如下面代码创建对象的时候E确定为String类型
MyArrayList<String> list = new MyArrayList<>();
4.2 泛型方法
方法中形参类型不确定时:
- 使用类名后面面定义的泛型 ,这个泛型所有方法都能用
- 在方法申明上定义自己的泛型 ,这个只有本方法才能用
格式:
修饰符<类型>返回值类型 方法名(类型 变量名) {
}
public static <E> void addAll(ArrayList<E> list, E...e){
for (E element : e) {
list.add(element);
}
}
此处还使用了可变参数 E...e,可以一次添加多个参数
4.3 泛型接口
格式:
修饰符 interface 接口名<类型>{
}
使用泛型接口方式1:实现类给出具体类型
//1:实现类给出具体的类型
MyArrayList2 list2 = new MyArrayList2();
public class MyArrayList2 implements List<String> {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<String> iterator() {
return null;
}
}
使用泛型接口方式2:实现类延续泛型,创建对象时再确定
//2:实现类延续泛型,创建实现类对象时在确定类型
MyArrayList3<String> list3 = new MyArrayList3<>();
public class MyArrayList3<E> implements List<E> {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<E> iterator() {
return null;
}
}
五、泛型的继承和通配符
继承:
泛型不具备继承性但是数据具备继承性
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
method1(list1);
如果方法method只规定了Ye泛型那么里面填入泛型Fu, ArrayList类型对象list2不可以,但是填入new Fu() 可以。
通配符:
可以限定类型的范围
? 表示不确定的类型
?extends E:表示也可以传递E或者E所有的子类类型
?super E:表示可以传递E或者E所有父类类型
public class GenericsDemo6 {
public static void main(String[] args){
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
method1(list1);
method1(list2);
method1(list3);
method2(list1);
method2(list2);
method2(list3);
}
//泛型的通配符
/*
* ?表示不确定的类型,他也可以进行类型的限定
* ? extend E : 表示可以传递E或者E所有的子类类型
* ? super E : 表示可以传递E或者E所有的父类类型
* */
public static void method1 (ArrayList<? super Zi> list){}
public static void method2 (ArrayList<? extends Ye> list){
}
}
class Ye{ }
class Fu extends Ye{ }
class Zi extends Fu{ }
六、 使用场景
- 定义类、方法、接口的时候,如果类型不确定就可以定义泛型
- 如果类型不确定但是能知道是哪个继承体系中的可以使用泛型的通配符