泛型
什么是泛型?
泛型是一种未知的数据类型,当我们不知道使用什么数据类型作为参数的时候,就可以使用泛型作为参数
举例说明:
我们在定义ArrayList集合的时候,不知道集合中会存储什么数据类型所以使泛型
例如:
① 定义ArrayList集合类的源码中,因为不确定ArrayList集合中存放什么类型的数据,则使用泛型表示,E代表Element元素
② ArrayList类中的add方法也使用了泛型,因为再确定ArrayList集合中存放的数据类型之前,不知道使用什么类型作为参数传入,所以使用了泛型作为参数
为什么要使用泛型?
1、使用泛型的优势及劣势
优势:当集合不使用泛型的时候,默认的类型就是Object类型,可以存储任意类型的数据
劣势:不安全,有可能会引发异常
2、举例说明不使用泛型优势和劣势
好处:可以传入任何类型的数据不受限制
弊端:因为可能涉及到数据类型转换,然后导致运行出错
public static void main(String[] args) {
// 创建一个ArrayList集合
ArrayList list = new ArrayList();
// 这里体现出了不使用泛型的优势,可以传入任意类型的数据,不受限制
list.add("asd");
list.add(1);
// 获取迭代器
Iterator it = list.iterator();
// 使用迭代器进行遍历
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj); //打印输出ArrayList集合中的各个元素
// 新增一个需求,用于体现不使用泛型的劣势
// 我们现在计算每个存入的数据的长度
String s = (String)obj;// 使用向下转型,才能调用length方法
System.out.println(obj.length);
// 然后发现运行报错,显示无法转换数据类型
}
}
异常提醒:
因为int类型无法强制转换为String类型
3、举例说明使用泛型的优势和劣势
好处:避免了类型转换的麻烦,存储的是什么类型的数据,取出的就是什么类型的数据,把运行期间的异常,提前到了编译的时候就报错
弊端:泛型指定的是什么类型的数据,就只能存储什么类型的数据
public static void main(String[] args) {
// 创建一个ArrayList集合
ArrayList<String> list = new ArrayList();
// 这里体现出了不使用泛型的优势,可以传入任意类型的数据,不受限制
list.add("asd");
list.add("dse");
// list.add(1);当我们写这行代码的时候,编译的时候就会报错
Iterator it = list.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj); //打印输出ArrayList集合中的各个元素
}
}
含有泛型的类
1、定义格式
修饰符 class 类名<代表泛型的变量> {
// 类体
}
2、泛型的使用过程(拿ArrayList集合举例)
当我们不缺定什么数据类型的时候,可以使用泛型。泛型可以接收任意的数据类型,可以使用Integer、String和Student等,我们再创建对象的时候才确定泛型的数据类型
// 创建一个GenericClass类使用泛型
public class GenericClass<E> {
private E name;
public E getName() {
return name;
}
public void setName() {
this.name = name;
}
}
public void static main(String[] args) {
// 创建GenericClass对象,泛型使用Integer类型
GenericClass<Integer> gc = new GenericClass<>();
gc.setName(1)
Integer name = gc.getName();
System.out.println(name);// 打印输出1
// 创建GenericClass对象,泛型使用String类型
GenericClass<String> gc2 = new GenericClass<>();
gc2.setName("张三")
Integer name2 = gc.getName();
System.out.println(name2);// 打印输出张三
}
由上我们可以看出使用泛型的类可以传入任意类型的数据,只需要在创建对象的时候指定数据类型即可
含有泛型的方法
1、定义格式
修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){
// 方法体
}
2、举例说明
public void static main(String[] args) {
// 调用含有泛型的普通方法
// 传入什么类型的数据泛型就使用什么类型
method(10);//得到10
method("asd");// 得到asd
method(true);// 得到true
method(10.12);// 得到10.12
// 调用静态方法
// 传入什么类型的数据泛型就使用什么类型
静态方法所在类名.method2(10);//得到10
静态方法所在类名.method2("asd");// 得到asd
静态方法所在类名.method2(true);// 得到true
静态方法所在类名.method2(10.12);// 得到10.12
}
//定义一个使用泛型的方法
public <M> void method(M m) {
// 打印输出传入的参数
System.out.println(m);
}
// 定义了一个静态方法
public static <S> void method2(S s) {
// 打印输出传入的参数
System.out.println(s);
}
含有泛型的接口
1、定义格式
修饰符 interface 接口名称<泛型> {
// 含泛型的抽象方法
public abstract void 方法名(I i);
}
2、含有泛型的接口的使用方式
(1)第一种使用方式:
定义接口的实现类,实现接口并指定接口的泛型(实现类自己指定泛型)
举例说明:
Scanner类实现了Iterator接口,并且指定了接口的泛型为String,所以重写的next方法默认就是String类型
// Interator接口是一个含有泛型的接口
public interface Iterator<E> {
// next是含有泛型的一个抽象方法
E next();
}
// Scanner类实现了Iterator接口并且指定了接口的泛型为String
public final class Scanner implements Iterator<String>{
// 重写了Iterator接口中的next方法,默认数据类型为String
public String next(){};
}
(2)第二种使用方式
接口使用什么泛型,实现类就使用什么泛型(实现类跟着接口走)
举例说明:
相当于定义了一个含有泛型的类,创建对象的时候才确定泛型是什么
// List接口是一个含有泛型的接口
public interface List<E> {
// 两个含有泛型的抽象方法;
boolean add(E e);
E get(int index);
}
// ArrayList实现类是一个含有泛型的类
public class ArrayList<E> implements List<E>{
// 覆盖重写了add方法,并且参数传入一个泛型,
// 等实例化创建对象的时候确定泛型
public boolean add(E e){};
public E get(int index){};
}
泛型的通配符
1、什么是泛型的通配符
?:问好就是泛型的通配符,它代表任意数据类型
2、通配符的使用方法
不能创建对象使用,只能作为方法的参数使用
举例说明:
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
ArrayList<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("d");
printArray(list1);// 得到1和2
printArray(list2);// 得到a和d
}
/*
* 定义一个方法,能够遍历所有类型的ArrayList集合
* 这时候我们不知道ArrayList集合使用什么数据类型,
* 可以使用泛型的通配符?来接收数据类型
*/
public static void printArray(ArrayList<?> list{
// 创建迭代器
Iterator<?> it = list.iterator();
// 遍历ArrayList集合中的元素
while(it.hasNext()){
Object o = it.next();
System.out.println(o)
}
}
通配符的高级使用–受限泛型(看懂就行,工作中不常用)
1、受限泛型包括泛型的上限限定和泛型的下限限定
2、泛型的上限限定
? extends E
:它代表使用的泛型只能是E类型的子类或者本身
3、泛型的下限限定
?extends E
:它代表使用的泛型只能是E类型的父类或者本身
举例说明: