java中的泛型的使用与理解
什么是泛型?
泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写 体验泛型
代码时定义一些可变部份,那些部份在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。
定义:
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法
的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型
转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处:
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");
注意:
- 泛型是 Java 1.5 的新增特性,它以C++模板为参照,本质是参数化类型(Parameterized Type)的应用。
- 类型参数只能用来表示引用类型,泛型在Java中要求,泛型传入的必须是包装类型,必须是Object类型的,或者是自定义的类,不能传入基本类型例如 int、double、char 等。,必须要传包装类型如Integer不能用来表示基本类型,但是传递基本类型不会报错,因为它们会自动装箱成对应的包装类。
运用:
1 /*iG相当于占位符,用来传递数据类型,而不是数据的值,称为类型参数(名字可以自定义,当然更多的时候我们得按照规范来) 2 * 3 */ 4 //自定义泛型类,多个泛型之间可以用逗号隔开如<iG,iT,..> 5 class MyArrays<iG>{ //类的泛型必须要放在类名的后面 6 //调换数组的元素的位置 7 public void rever(iG[] a){ 8 System.out.println(a); 9 } 10 } 11 public class customToolClass { 12 public static void main(String[] args){ 13 String[] str=new String[10]; 14 Integer[] intArr = new Integer[10]; 15 //不能传基本数据类型,就算是整形数组,如int[],也要传int的包装类Integer 16 int[] arr = new int[10]; 17 // MyArrays<int> my1 = new MyArray<int>(); //不能是基本数据类型 18 MyArrays<Integer> my2 = new MyArrays<Integer>(); // 只能是包装类 19 //my2.rever(arr); //不能是整形数组 20 //标准格式是这样的,两边的类型要匹配 21 MyArrays<String> aa = new MyArrays<String>(); 22 aa.rever(str); 23 //下面这两种也是可以的,但是不推荐,这是java为了向下兼容以前的版本设计的 24 MyArrays<String> cc = new MyArrays(); 25 MyArrays dd = new MyArrays<String>(); 26 //-------------------------------------------------------------- 27 MyArrays<Integer> aa1 = new MyArrays<Integer>(); 28 aa1.rever(intArr); 29 } 30 }
与普通类的定义相比,上面的代码在类名后面多出了 <iG> ,iG 是自定义的标识符,也是参数,用来传递数据的类型,而不是数据的值,我们称之为类型参数。在泛型中,不但数据的值可以通过参数传递,数据的类型也可以通过参数传递。iG只是数据类型的占位符,运行时会被替换为真正的数据类型。
传值参数(我们通常所说的参数)由小括号包围,如 (int x, double y),类型参数(泛型参数)由尖括号包围,多个参数由逗号分隔,如 <T> 或 <T, E>。注意:这只是个规范,名称可以自定义的。
类型参数需要在类名后面给出。一旦给出了类型参数,就可以在类中使用了。类型参数必须是一个合法的标识符,习惯上使用单个大写字母,通常情况下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型。
泛型类在实例化时必须指出具体的类型,也就是向类型参数传值,格式为:
className variable<dataType1, dataType2> = new className<dataType1, dataType2>();
也可以省略等号右边的数据类型,但是会产生警告,即:
className variable<dataType1, dataType2> = new className();
因为在使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险,比本文一开始介绍的自动装箱和向上转型要更加实用。
测试效果图: