Java泛型的一些限制
本文主要參考《Java编程思想(第4版)》的Java泛型章节,仅当一个简单的读书笔记。
和C++泛型对照,Java泛型仅仅是一种编译期间的擦拭机制。
这是因为考虑到和曾经的兼容而考虑的一种折中方案。
在编译好的泛型代码里,编译期间已经把全部的泛型信息给擦拭掉,因此无法获得不论什么有关泛型參数类型的信息。因此List<String>和List<Integer>实际上是同一类型。
參考下面代码:
- //下面3个样例都无法通过编译
- public <T> void testGeneric(Object arg) {
- if (arg instanceof T) {} //1
- T var = new T(); //2
- T[] array = new T[100]; //3
- }
从以上代码能够看到,这样的擦拭机制的限制包含例如以下:
1、instanceof无法使用
2、无法实例化泛型类
3、无法实例化泛型数组
以上3种方法无法通过编译的主要原因是,泛型的擦拭机制把详细的类型信息都擦拭,无法在执行时知道确切的类型信息。只是Java提供了另外的方法去绕过这些限制。
解决1
对于第1种,无法使用instanceof语法。我们能够利用动态的isInstance():
- //testInstance(String.class, "abc") == true
- public static <T> boolean testInstance(Class<T> c, Object arg) {
- return c.isInstance(arg);
- }<
解决2
对于第2种。无法实例化泛型类。假设对于要实例化的泛型类。拥有无參默认构造函数,我们能够利用Class对象:
- public static <T> T createGeneric(Class<T> c) {
- T x = null;
- try {
- x = c.newInstance();
- } catch (Exception e) {
- throw new RuntimeException(e); //createGeneric<Integer.class>会抛出异常,因为Integer没有默认构造函数
- }
- return x;
- }
因为以上代码採用Class对象实例化拥有一定限制,因此我们还能够借助工厂方法,显示创建相应的类:
- interface GenericFactory<T> {
- T create();
- }
- class IntegerFactory implements GenericFactory<Integer> {
- @Override
- public Integer create() {
- return new Integer(0);
- }
- }
解决3
对于第3种,无法实例化泛型数组。我们能够借助ArrayList<T>来取代,但假设一定要获得数组的行为,以及泛型提供的编译期的安全类型,
- //GenericArray ga = new GenericArray<Integer>(10);
- //ga.put(3, 10);
- //int abc = (Integer) ga.get(3);
- //Integer[] aaa = (Integer[]) ga.array(); //抛出ClassCastException
- class GenericArrayEx<T> {
- private T[] array;
- public GenericArray(int size) {
- array = (T[]) new Object[size];
- }
- public void put(int index, T item) {
- array[index] = item;
- }
- public T get(int index) {
- return array[index];
- }
- public T[] array() {
- return array;
- }
- }
对于以上代码。我们採用一个GenericArray的类进行包装,但内部实际还是一个Object[]的对象数组,在put和get的时候获得了编译期间的检查。但问题来了,假设我们使用array()方法企图获得内部数组并转型的时候,会抛出ClassCastException,这是因为数组实际还是Object[]对象!为了解决问题,我们能够使用Array.newInstance。
- //GenericArrayEx ga = new GenericArrayEx<Integer>(Integer.class, 10);
- //ga.put(3, 10);
- //int abc = (Integer) ga.get(3);
- //Integer[] aaa = (Integer[]) ga.array(); //能够成功转型
- class GenericArrayEx<T> {
- private T[] array;
- public GenericArrayEx(Class<T> type, int size) {
- array = (T[]) Array.newInstance(type, size);
- }
- public void put(int index, T item) {
- array[index] = item;
- }
- public T get(int index) {
- return array[index];
- }
- public T[] array() {
- return array;
- }
- }
这样,就能够使用T[]了。
Java泛型的一些限制的更多相关文章
- Java泛型的历史
为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...
- 浅析Java 泛型
泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...
- Java:泛型基础
泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...
- java泛型基础
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法. Ja ...
- 使用java泛型设计通用方法
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...
- 关于Java泛型的使用
在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Wind ...
- 初识java泛型
1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...
- 【Java心得总结四】Java泛型下——万恶的擦除
一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...
- 【Java心得总结三】Java泛型上——初识泛型
一.函数参数与泛型比较 泛型(generics),从字面的意思理解就是泛化的类型,即参数化类型.泛型的作用是什么,这里与函数参数做一个比较: 无参数的函数: public int[] newIntAr ...
- 初识Java泛型以及桥接方法
泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...
随机推荐
- HTML5练习4
1.菜单条 主要代码 <!doctype html> <html> <head> <meta charset="utf-8"> &l ...
- 【LOJ】#2479. 「九省联考 2018」制胡窜
题解 老了,国赛之前敲一个后缀树上LCT和线段树都休闲的很 现在后缀树上线段树合并差点把我写死 主要思路就是后缀树+线段树合并+容斥,我相信熟练的OIer看到这已经会了 但就是不想写 但是由于我过于老 ...
- Zookeeper Canary
ZooKeeper Canary我理解用于测试ZK节点是否正常的心跳服务,这是从ClouderaManager中粘下来的: 这是 ZooKeeper 服务级运行状况测试,用于检查基本客户端操作是否正常 ...
- LOOPS 概率dp
题意:迷宫是一个R*C的布局,每个格子中给出停留在原地,往右走一个,往下走一格的概率,起点在(1,1),终点在(R,C),每走一格消耗两点能量,求出最后所需要的能量期望 简单概率dp 注意 原地不 ...
- php 导入excel文件
excel.php <?phprequire_once 'PHPExcel/PHPExcel.php';require_once 'PHPExcel/PHPExcel/IOFactory.php ...
- 给虚拟机下面的ubuntu系统增加硬盘存储空间
给虚拟机下面的ubuntu系统增加硬盘存储空间 由于ubuntu系统是安装在vsphere上面的,所以可能会和vmware上面的有一点区别,打开exsi系统的配置页面,如下图所示. 选择添加存储器 ...
- 002.KVM环境部署
一 环境准备 1.1 查看是否支持虚拟化 [root@kvm-host ~]# grep -E 'vmx|svm' /proc/cpuinfo 注意:intel为vmx,amd为svm. 1.2 确定 ...
- HDU 1402 A * B Problem Plus 快速傅里叶变换 FFT 多项式
http://acm.hdu.edu.cn/showproblem.php?pid=1402 快速傅里叶变换优化的高精度乘法. https://blog.csdn.net/ggn_2015/artic ...
- bzoj1151 动物园
Description 新建的圆形动物园是亚太地区的骄傲.圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围栏里有一 种动物.如下图所示: 你是动物园的公共主管.你要做的是,让每个来动物园的人 ...
- ELASTIC的备份与恢复
前言 elasticsearch官方并没有提供合适的备份工具,然而生产场景中备份却是的确需要的. 本文介绍了使用自己写的php脚本以及第三方工具来进行索引的备份,恢复以及删除等操作. 全量备份 ela ...