泛型

什么是泛型?

泛型是一种未知的数据类型,当我们不知道使用什么数据类型作为参数的时候,就可以使用泛型作为参数

举例说明:

我们在定义ArrayList集合的时候,不知道集合中会存储什么数据类型所以使泛型

例如:

① 定义ArrayList集合类的源码中,因为不确定ArrayList集合中存放什么类型的数据,则使用泛型表示,E代表Element元素
ArrayList定义集合类的类源码

② 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类型的父类或者本身

举例说明:
在这里插入图片描述

posted @ 2020-10-15 16:40  谢海川  阅读(49)  评论(0)    收藏  举报