JAVA泛型机制
【什么是泛型机制?】
泛型是JDK1.5以后出来的新特性,其目的是为了解决类型转换的安全问题,是一个类安全机制。
泛型格式:
通过<>来定义要操作的引用数据类型
【泛型机制有什么好处?】
- 类型安全
将运行时期出现的问题(ClassCastException),转移到编译时期。 - 消除强制类型转换
使得代码更加可读,并且减少了出错机会。所有的强制转换都是自动和隐式的 - 提高性能
在泛型的实现中,编译器将强制类型转换插入生成的字节码中,但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来了可能。
【泛型机制在什么时候使用?】
通常是在集合框架中使用,遇到<>就要定义泛型。
其实<>就是用来接收类型的,在使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
【泛型类】
当类中要操作的引用数据不确定时,就可以定义泛型类。
在1.5之前是通过Object来实现扩展的,1.5之后使用泛型来实现扩展。
代码实例
Class Demo<T>{
private T t;
public void setDemo(T t){
this.t = t;
}
public T getDemo(){
return t;
}
}
注意:
泛型类定义的泛型,在整个类中有效,当泛型类的对象明确要操作的类型后,所有要操作的类型就都已经固定了。
【泛型接口】
泛型同样可以定在接口上,其接口类和实现类的具体表现形式如下:
当实现类确定传入的类型时,可以直接指定类型
interface Inter<T> {
public void show(T t);
}
class demo implements Inter<String>{
public void show(String str){
System.out.println(str);
}
}
当实现类不确定传入的类型时,依旧采用泛型
interface Inter<T> {
public void show(T t);
}
class demo<T> implements Inter<T>{
public void show(T t){
System.out.println(t);
}
}
【泛型方法】
由于泛型类的所有方法都只能使用同一不确定的类型。
那么当我们需要不同方法操作不同的不确定类型时,就可以将泛型定义在方法上。
代码实例:
Class Demo{
public <T> void test1(T t){
System.out.println("this is test1" + t);
}
public <T> void test2(T t){
System.out.println("this is test2" + t);
}
}
【泛型限定】
在学习泛型限定之前要先学习一个内容,通配符
什么是通配符?
通配符,也可以理解为占位符。
那么,通配符为什么会产生呢?
List<Integer> ex_int= new ArrayList<Integer>();
List<Number> ex_num = ex_int; //非法
在执行上面代码时,第二行会报错。这是因为类型转换错误。我们都知道子类对象可以自动赋值给父类对象,Integer是Number的子类,但是List<Integer>却并非List<Number>的子类,所以会发生类型转换异常。
我们假设第二行代码可以正常运行,那么我们是否可以在ex_num中装入Number的所有子类对象呢?若是可以的话,我们给它装入一个Double对象,一个Integer对象,那么我们在取其中元素时,是该将其转型为Double还是Integer呢?所以这明显是不可行的。
这个时候,我们就需要一种可以同时表示List<Integer>和List<Number>的引用类型,于是通配符就诞生了,它的表现形式就是 List<?>
补充, List与List<?>
List实际上也是List<Object>。List实际上表示持有任何Object类型的原生List。
List<?>表示具有某种特定类型的非原生List,只是我们不知道那种类型是什么。
了解了通配符,我们开始学习泛型限定
泛型限定分为两种:
- 上限
- 下限
上限:可以接收E类型本身或者E类型的子类型,表现形式为: ? extends E
下限:可以接收E类型本身或者E类型的父类型,表现形式为: ? super E
关于泛型的上下限,在Comparator中有很好的体现,这里就不赘述了。