概念:泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入。
原理:Java有Java编译器和Java虚拟机,编译器将Java源代码转换为.class文件,虚拟机加载并运行.class文件。对于泛型类,Java编译器会将泛型代码转换为普通的非泛型代码,将类型参数T擦除,替换为Object,插入必要的强制类型转换。
Java虚拟机实际执行的时候,它是不知道泛型这回事的,它只知道普通的类及代码。再强调一下,Java泛型是通过擦除实现的,类定义中的类型参数如T会被替换为Object,在程序运行过程中,不知道泛型的实际类型参数,认识到这一点是非常重要的,它有助于我们理解Java泛型的很多限制。
参数化类型可以引用原始类型的对象,实例:
Collection<String> c = new ArrayList();
原始类型可以应用参数化类型的对象
Collection c = new ArrayList<String>();
参数化类型不考虑类型参数间的继承关系
ArrayList<String> a = new ArrayList<Object>();
//错误:x:
ArrayList<Object> a = new ArrayList<String>();
//错误:x:
泛型只是在编译期间编译器做类型检查的机制。
ArrayList a1 = new ArrayList<Integer>();
ArrayList<Object> a = a1;
或
ArrayList a1 = new ArrayList<Integer>();
ArrayList<String> a = a1;
不能使用基本类型实例化类型参数
不能抛出也不能捕获泛型类实例
泛型类的静态上下文中类型变量无效,不能在静态域或方法中应用类型变量。
class GeneDemo<T,U> {
void method1(T t1){
System.out.println(t1);
}
T method2(T t1){
System.out.println(t1)
}
U method(T t1, U u1){
return;
}
}
放置泛型的类型参数的尖括号应紧邻返回值之前。普通方法、构造方法和静态方法中都可以使用泛型。
当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法调用。
因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数。若使用需要是静态泛型方法,则重新声明泛型参数。
public class GenericDao<T> {
public void save(T obj) {
}
public T getById(int id) {
return null;
}
/**
* 静态方法。重新声明T,此处的T与GenericDao<T>的T没有关系。
*/
public static <T> void update(T obj){
}
}
四.补充内容
使用 < T extends BoundingType >
限定泛型类型。T应该是绑定类型的子类型。T和绑定类型可以是类或接口。一个泛型变量或通配符可以有多个限定。限定类型使用"&"分割。若用一个类做限定,它必须是限定列表中的第一个。
例: <V extends Serializable & Cloneable> void method(){}
限定通配符的上边界
<? extends Number>
用于匹配Number及Number的子类。
正确: Vector<? extends Number> x = new Vector<Integer>();//Integer继承了Number
错误: Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界
<? super Integer>
用于匹配Integer及Integer的父类。
正确: Vector<? super Integer> x = new Vector<Number>();
错误: Vector<? super Integer> x = new Vector<Byte>();
使用"?"通配符可以引用其他各种参数化的类型,"?"通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
例 Collection<?>
可以适配 Collection<Object>
、 Collection<Integer>
或 Collection<String>
等。
各位看官还可以吗?喜欢的话,动动手指点个:heartpulse:,点个关注呗!!谢谢支持!
欢迎关注公众号【 Ccww笔记 】,原创技术文章第一时间推出