泛型:参数化类型,就是将原来具体的类型参数化
我们定义方法时有形参,在实际调用该方法时我们会传递实参
相应的,我们在定义方法或类时指定一个泛型(类型形参),在具体使用时传入具体的类型(类型实参)
1. 为什么需要泛型
在日常开发过程中,我们可能需要根据数据的类型写大量逻辑重复的代码,又或者为了规范操作,封装统一的表面使用逻辑等,使用泛型来完成上述操作
例如数据结构当中,数据作为对象存储在各种结构当中,这里我们忽略数据本身的类型,只在乎它数据与数据间的关系,只处理增删改查等操作;如果不使用泛型,那么就得在使用时为特定类型而编写一个对应的数据结构了
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable ...
又例如在Android开发当中,会经常使用到ListView、RecyclerView控件显示多项数据,他们的共性大都有上下滚动、点击跳转,在为它编写适配器时如果不使用泛型,那么数据源发生一点改变,直接导致原有的类不能复用,需要编写新的类,使用泛型之后则只需要在对itemview填充时增加判断即可
或许会有疑惑为什么不能直接用object来代替泛型,在使用时进行强转,这样也可以,但我们会有很多重复的类型判断代码,这样显得凌乱,甚至更繁杂。
其实Java中的泛型实现就是上面这样实现的。可以看最后的虚拟机实现泛型
2. 泛型的优点
- 适用于多种数据类型执行相同的代码
- 泛型中的类型在使用时指定,不需要强制类型转换,同时还能避免传入类型错误
3. 定义泛型
泛型类
public class GenericityClass<T, E, K, V> {
T t;
E e;
K k;
V v;
}
泛型接口
public interface GenericInterface<T, E, K, V> {
T getT();
E getE();
K getK();
V getV();
}
泛型方法
泛型方法可以独立使用,不强制在泛型类或接口中
public static <T> T genericStaticMethod(T t){
return t;
}
public <T> T genericMethod(T t){
return t;
}
//使用
String s = new GenericDemo().genericMethod("泛型");
Object o = new GenericDemo().<Object>genericMethod("泛型");
泛型的声明可以使用任意的大写字符,但前后需要匹配,同时需要使用常用或者说默认的字母来定义泛型
4. 使用泛型
限定类型变量
extends
: 限定泛型具有或实现的功能 后面可接一个类&多个接口,类必须写在最前且只有一个
通配符类型 ?
-
?extends T:用于传入数据
-
解决泛型子类代替父类的问题
-
只用于方法
-
用于安全的访问数据
-
表示传入类型的上级
-
-
?super T:用于获取数据(获取的是object)
-
定义传入的参数的下界
-
不能传入T的子类,只能是T或T的父类
-
用于安全的写入数据
-
表示传入类型的下级
-
-
无限定的通配符 ?
- 表示对类型没有什么限制,可以把?看成所有类型的父类
- 一般是方法中,只是为了说明用法
继承规则
- 泛型类中泛型不能使用 子类代替父类的形式
- 泛型类可以继承扩展其他泛型类
泛型中约束和局限性
- 不能实例化类型变量:使用时需要传入具体的类型
- 静态域或方法不能引用类型变量(静态方法本身是泛型方法也可以):泛型类的静态上下文中类型变量失效,因为泛型是需要对象加载时才知道是什么类型
- 只允许传入包装类
- 不能使用 instance of
- 运行时类型查询只适用于原始类型:getclass获取的类名是原生泛型类类型,与传入参数类型无关
- 不能对泛型 创建数组 new R<T>[10];
- 不能派生异常(Exception Throwable)因为不能捕获泛型异常对象
但是可以捕获异常,抛出泛型
5. 虚拟机如何实现泛型的
JDK1.5以前没有泛型的概念
Java的泛型是通过泛型擦除实现的
javac编译时会进行泛型擦除,泛型被定义为Object,这种方式称为伪泛型;在使用时会进行类型强转,所以泛型只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此,对于运行期的Java语言来说,ArrayList<int>与ArrayList<String>就是同一个类,所以泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型称为伪泛型
语法糖
糖衣语法,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会
网友评论