? ? ? ???泛型的本质是 参数化类型 ,也就是说所操作的数据类型被指定为一个参数的方式传递,类似于方法中的变量参数。可以用在类、接口、方法的创建中,分别简称为泛型类、泛型接口、泛型方法。
? ? ? ? ? 在没有使用泛型的情况下,如果要实现参数“任意化”,通常会定义成Object类型来接受,然后强制类型转换使用;而强制类型转换有明显的缺点,就是必须要知道实际参数的具体类型的情况才可以进行转换,同时在强制转换的过程中,编译器不会报错提示的,只有在运行阶段才会出现异常,一定程度上存在安全隐患。
? ? ? ? ? ?泛型的使用方式,可以在类、接口、方法中使用,分别简称之泛型类、泛型接口、泛型方法,并且通过泛型实现数据类型的任意化,即灵活、又有安全性,易于维护。
注:
? ? ? ? JDK在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
? ? 类型通配符是一个问号(?),将一个问号作为类型形参传递给List集合,写作:List<?>,(意思是元素类型未知的List)。
这个问号(?)被成为通配符,它的元素类型可以匹配任何类型。
例子:
public void test(List<?> c){ ? for(int i =0;i<c.size();i++){ ? ? System.out.println(c.get(i)); ? } } 调用: List<String> list = new ArrayList<String>(); list.add("333"); List<Integer> list2 = new ArrayList<Integer>(); list2.add(3334); test(list); test(list2);
上限通配符
? ? ?如果想限制使用泛型类别时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口,也可以是这个类或接口本身。
//它表示集合中的所有元素都是Shape类型或者其子类 List<? extends Shape>
? ? 这就是所谓的上限通配符,使用关键字extends来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身。
下限通配符
如果想限制使用泛型类别时,只能用某个特定类型或者是其父类型才能实例化该类型时,可以在定义类型时,使用super关键字指定这个类型必须是是某个类的父类,或者是某个接口的父接口,也可以是这个类或接口本身。
//它表示集合中的所有元素都是Circle类型或者其父类 List <? super Circle>
? ?这就是所谓的下限通配符,使用关键字super来实现,实例化时,指定类型实参只能是extends后类型的子类或其本身。
四、类型擦除
例子:
Class c1=new ArrayList<Integer>().getClass(); Class c2=new ArrayList<String>().getClass(); System.out.println(c1==c2);
输出:
true
? ?这是因为不管为 泛型的类型形参传入哪一种类型实参,对于Java来说,它们依然被当成同一类处理,在内存中也只占用一块内存空间 。从Java泛型这一概念提出的目的来看,其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
? ? 另外,一提到泛型,相信大家用到最多的就是在集合中,其实,在实际的编程过程中, 自己可以使用泛型去简化开发,且能很好的保证代码质量 ,例如调第三方接口的返回类型,在接口返回接受对象泛型化,有利用程序的扩展和可维护性等,以及Json在做数据转换成实体对象时就可以去通过泛型做Util。
?
?
?
?