1 泛型的背景
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。
对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
针对于以上内容举例说明:为什么在没有泛型之前会出现类转换异常的安全隐患。
List什么都不指定时默认为Object类型。可以往里面赛各种类型,但是当你想使用时却出现了麻烦,因为你要对里面的每一个元素进行类型转换,否则就在运行时就会报类转换异常,而且你要事先知道集合中有多少种类型,否则安全隐患就还有,所以这肯定不是明智之举,所以就引入了泛型。
2 泛型的使用
2.1 泛型类
泛型的定义:
package com.chao.test;
public class FanXingLei<T> {
private T params;
public T getParams() {
return params;
}
public void setParams(T params) {
this.params = params;
}
public FanXingLei(T params) {
this.params = params;
}
}
class Test01{
public static void main(String[] args) {
//当不指定数据类型时,默认为Object类型
FanXingLei fanXingLei = new FanXingLei("abc");
//指定类型
FanXingLei<String > fanXingLei1 = new FanXingLei<>("abc");
}
}
泛型类的注意事项:
针对于第三点进行讲解:
根据实践得出两者虽然指定了不同的数据类型但是本质上都是同一个FanXingLei类型。所以不能根据类型去重载
2.2 练习
package com.chao.fanxinglei;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/*
* 模拟抽奖活动,奖品有实物也有钱
* 随机抽取
*
* */
public class ChouJiang<T> {
Random random = new Random();
private T product;
//奖品池
List<T> list = new ArrayList<>();
public void addList(T product) {
list.add(product);
}
public T getProduct() {
product = list.get(random.nextInt(list.size()));
return product;
}
}
class test{
public static void main(String[] args) {
ChouJiang<String> stringChouJiang = new ChouJiang<>();
String[] strings = {"苹果手机","华为手机","小米手机"};
for (String string : strings) {
stringChouJiang.addList(string);
}
String product = stringChouJiang.getProduct();
System.out.println("恭喜您抽中:"+product);
System.out.println("-------------------------------------");
ChouJiang<Integer> integerChouJiang = new ChouJiang<>();
Integer[] integers = {1000,5000,10000,3000};
for (Integer integer : integers) {
integerChouJiang.addList(integer);
}
Integer product1 = integerChouJiang.getProduct();
System.out.println("恭喜您抽中奖金:"+product1);
}
}
3 泛型类派生子类
第一点:并不完整,子类和父类的泛型要一致并不是完全正确的,应该是子类的泛型类型应该含有父类泛型类型即可,比如可以写成以下形式:
//父类和子类泛型类型的名称一定要一样
public class Person<T,K> extends Parent<T> {
}
4 泛型接口
4.1 泛型接口的定义
4.2 泛型接口的使用
第一点:
即使不明确,它默认的就是Object类
5 泛型方法
5.1 泛型方法的定义
5.2 泛型方法的注意事项
- 泛型类中的成员方法并不是泛型方法
- 泛型方法中的泛型类型跟泛型类中的泛型类型没有任何关系,只跟调用该方法时传入的类型有关系
- 泛型类中只有泛型方法可以写成静态的。
5.3 泛型可变参数
6 类型通配符
为什么会有通配符呢?实际就是为了解决泛型不能根据类型重载问题,因为尽管<>里的类型不一样,但是本质对象都是一样的,比如:Person和Person其实就是同一个类型Person类型,还有就是泛型没有多态概念,不能使用多态进行值传递,比如;上述代码不能写成:
public static void showBox(Box<Object> box) {
}
6.1 类型通配符上限
注意事项:
一旦使用了类型通配符 ?,只能接收数据不能往该集合中存储数据, 唯一的例外是null
6.2 类型通配符下限
注意:
<? extends T> 只能用来读取数据,不能向集合中存储数据,不能使用 add 方法;<? super T> 既能读取数据(需声明为 Object 类型),也能存储数据。 频繁往外读取内容的,适合用 <? extends T > ;经常往集合里插入数据的,适合用 <? super T>