Java 泛型的总结与复习
泛型的总结与复习
在1.5之前是没有泛型的,而通常使用object来泛化我们所有的对象,这样做也可以让我们达到泛型的目的,但是在代码编写的过程中很容易出现类型转换的错误,这种错误在编译期间是不知道的,只有到运行期间才知道。
java语言的泛型基本上完全是在编译器中实现的,有编译器执行类型检测和类型推断,然后生成普通的非泛型的字节码,就是虚拟机完全无感知泛型的存在。这种实现技术称为擦除(erasure)。编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除。所以使用了泛型后在编译期便可知道是否有错。
泛型可以解决数据类型的安全性问题,主要原理就是在类声明时通过一个标识表示类中某个属性的类型或者某个方法的返回值及参数类型。这样在类声明或者实例化时只要指定好需要的类型即可。
泛型类定义如下:
1 | public class Fruit<T> |
Fruit类在声明的时候使用了<T>的形式,T表示此类型由外部调用本类时指定的。实例化对象时可以使用
Fruit<String> f =new Fruit<String>();
加入泛型后的最大好处实际上是避免了类转换异常的发生,这样使得程序的操作更加安全。
泛型中的构造方法
构造方法可以为类中的属性初始化,那么如果类中的属性通过泛型指定,而又需要通过构造设置属性内容时,构造方法的定义与之前并无不同,不需要像声明1类那样指定泛型,具体格式如下:
public Fruit(T name){this.name=name}
通配符
泛型操作中可以通过通配符接收任意指定泛型类型的对象。
在开发中对象的引用传递是最常见的,但是如果在泛型类中的操作中,在进行引用传递时泛型类型必须匹配才可以传递,否则是无法传递的,下面是一个例子
1 | public class Demo |
一个类的子类可以通过对象多态性为其父类实例化,但是在泛型操作中,子类的泛型类型是无法使用父类的泛型类型接收的
上述程序会出现编译时错误,尽管String 是Object 类的子类,但是在进行引用传递时也同样无法进行操作,如果此时想让程序正确执行,可以将fun()方法中定义的Info<Object> 修改为Info,即不指定泛型。
但是,这样并不推荐,所以最好采用通配符的方法
1 | public class Demo{ |
Info<?>表示可以使用任意的泛型类型对象。
在引用传递中,在泛型操作中也可以设置一个泛型对象范围上限和范围下限,范围上限使用extends关键字声明,表示参数化的类型可能是所指定的类型或者此类型的子类,而范围下限使用super进行声明,表示参数化的类型可能是所指定的1类型,或者是此类型的父类型,或者Object类。
声明对象(设置上限):Fruit<? extends 类> fruit
声明对象(设置下限):Fruit<? super 类> fruit
泛型接口
在JDK1.5后,不仅可以声明泛型类,还可以声明泛型接口,声明泛型接口和声明泛型类的语法类似,也是在接口名称后面加上<T>,
1 | interface Info<T> |
1 | 子类实现 |
泛型方法
泛型方法的定义与其所在的类是否是泛型类是没有任何关系的。所在的类可以是泛型类,也可以不是。
泛型方法定义
[访问权限] <泛型标识> 泛型标识(返回值类型) 方法名称([泛型标识 参数名称])
第二部分的泛型标识标识了这是一个泛型方法
1 | class Demo |
静态方法与泛型
静态方法有一种情况需要注意一下,那就是在类中的静态方法使用泛型:静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
即:如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 。
1 | public class StaticGenerator<T> |
泛型数组
在java中是”不能创建一个确切的泛型类型的数组”的。
下面采用通配符的方式是被允许的:数组的类型不可以是类型变量,除非是采用通配符的方式,因为对于通配符的方式,最后取出数据是要做显式的类型转换的。
1 | List<Integer> li = new ArrayList<Integer>(); |
Author: corn1ng
Link: https://corn1ng.github.io/2017/11/11/泛型的总结与复习/
License: 知识共享署名-非商业性使用 4.0 国际许可协议