讲解泛型之前,先看看如下的例子
List list = new ArrayList();
list.add(999);
list.add("abc");
list.add(new Date());
那么对于的数据是怎么加载进去的呢,jdk源码是这样的
![](https://i-blog.csdnimg.cn/blog_migrate/2cff10602cbd84e07c2c559876a2e9fd.png)
list.add都是默认增加Object类型数据,但是在数据获取中就必须要知道每个数据的类型,而且很容易产生
ClassCastException异常,那么在jdk1.5引入泛型的概念.
指定list中存储的参数类型,如: List<String> list = new ArrayList<String>();这样就指定list只能装载String类型的数据。
但是在编译的时候出现一个奇怪的现象:
java代码
List
<String>
list = new ArrayList
<String>
();
list.add("999");
list.add("abc");
编译后的代码
<String>参数消失了
1. 泛型原理:
类型擦出(
type erasure
)
类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。在使用泛型时,任何具体的类型都被擦除,唯一知道的是你在使用一个对象。比如:List<String>和List<Integer>在运行事实上是相同的类型。他们都被擦除成他们的原生类型,即List
在此有一个问题,既然泛型类型中清除了相关参数,那么系统又是如何在数据返回的时候自动转换呢?
通过两个步骤来解决
1.编译期会自动对传递进来的值进行检测,例如:List<String> list 对于增加list.add(9999)的时候编译会报错。
2.获取数据会把 获取的值按照传递的参数类型转换,list.get(0)的时候,系统会自动对这些值进行String的转换。
父类和子类在泛型中注意事项
List<String> childrenList = new ArrayList<String>();
List<Object> parentList = new ArrayList<Object>();
一下两种形式都不能转换
hildrenList = parentList;
parentList = childrenList;
在泛型一个
List
中装入了各种不同类型的对象类型,这显然是不可以的,
因为我们在取出
List
中的对象类型时,
就分不清楚到底该转型为哪种具体类型了(获取数据泛型会自动对传递的类型按参数设定的转换)
泛型定义注意
public static <T> List<T> get(String tu){
return null;
}
public <T> List<T> getBO (String tu){
return null;
}
2. 通配符:这里使用了通配符?指定可以使用任何类型的集合作为参数
注意:试图往使用通配符?的集合中加入对象,就会在编译时出现错误。
这是因为通配符?表示该集合存储的元素类型未知,可以是任何类型;因为该集合存储的元素类型未知,所以不能向集合中添加任何元素。
List<?> list = someMothod(arg);
list.add(object);//编译的时候会报错。
但是 从List<?> list中获取对象,虽然不知道List中存储的是什么类型,但是可以肯定的是存储的类型一定是Object的子类型,所以可以用Object类型来获取值。如for(Object obj: list)循坏获取对象,这个事允许的。
2.1 ?extends通配符
类型 children extends parent 通配符必须是父类的子类。也称作限定通配符。
List<? extends Number> list;
那么?类型只能是N
umber的子类,例如 Integer,Long,Float等,但是这里不能list.add(String)。
在获取数据的时候
取出其中对象时,可以使用
Number
类型来取值,因为虽然我们不知道列表中的元素类型具体是什么类型,
但是一定是
Number
类的子类型。
for(Number m:list){
.....
}
2.2 ?super通配符
类型 A
super B 通配符A必须是B类的超类
List<? super B> list;
这表示list存储的元素为B的超类,因此可以往其中加入B对象或者B的子类对象,但是不能加入其他对象,只要是B或者B的子类,则一定是与该元素类别兼容。
具体使用规则: 一个数据类型里获取数据,使用 ? extends 通配符
把对象写入一个数据结构里,使用 ? super 通配符
3.泛型方法:泛型方法的格式,类型参数<T>需要放在函数返回值之前。然后在参数和返回值中就可以使用泛型参数
public static <T> List<T> get(String tu){
return null;
}
public <T> List<T> getBO (String tu){
return null;
}
public <T> void getM1(T obj){
}
另外实际中经常出现的汇总一下;
1》. 泛型类型是被所有调用共享的
1》. 泛型类型是被所有调用共享的
所有泛型类的实例都共享同一个运行时类,类型参数信息会在编译时被擦除。
List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();
System.out.println(list1.getClass() == list2.getClass()); //True
2》 数组是协变的,如:Object[] objArray = new Long[10]是合法的,因为Long是Object的子类,与之相反,泛型是不可协变的,如List<Object> objList = new List<Long>()是非法的,将无法通过编译