本文主要參考《Java编程思想(第4版)》的Java泛型章节,仅当一个简单的读书笔记。

和C++泛型对照,Java泛型仅仅是一种编译期间的擦拭机制。

这是因为考虑到和曾经的兼容而考虑的一种折中方案。

在编译好的泛型代码里,编译期间已经把全部的泛型信息给擦拭掉,因此无法获得不论什么有关泛型參数类型的信息。因此List<String>和List<Integer>实际上是同一类型。

參考下面代码:

  1. //下面3个样例都无法通过编译
  2. public <T> void testGeneric(Object arg) {
  3. if (arg instanceof T) {} //1
  4. T var = new T(); //2
  5. T[] array = new T[100]; //3
  6. }

从以上代码能够看到,这样的擦拭机制的限制包含例如以下:

1、instanceof无法使用

2、无法实例化泛型类

3、无法实例化泛型数组

以上3种方法无法通过编译的主要原因是,泛型的擦拭机制把详细的类型信息都擦拭,无法在执行时知道确切的类型信息。只是Java提供了另外的方法去绕过这些限制。

解决1

对于第1种,无法使用instanceof语法。我们能够利用动态的isInstance():

  1. //testInstance(String.class, "abc") == true
  2. public static <T> boolean testInstance(Class<T> c, Object arg) {
  3. return c.isInstance(arg);
  4. }<

解决2

对于第2种。无法实例化泛型类。假设对于要实例化的泛型类。拥有无參默认构造函数,我们能够利用Class对象:

  1. public static <T> T createGeneric(Class<T> c) {
  2. T x = null;
  3. try {
  4. x = c.newInstance();
  5. } catch (Exception e) {
  6. throw new RuntimeException(e); //createGeneric<Integer.class>会抛出异常,因为Integer没有默认构造函数
  7. }
  8. return x;
  9. }

因为以上代码採用Class对象实例化拥有一定限制,因此我们还能够借助工厂方法,显示创建相应的类:

  1. interface GenericFactory<T> {
  2. T create();
  3. }
  4.  
  5. class IntegerFactory implements GenericFactory<Integer> {
  6. @Override
  7. public Integer create() {
  8. return new Integer(0);
  9. }
  10. }

解决3

对于第3种,无法实例化泛型数组。我们能够借助ArrayList<T>来取代,但假设一定要获得数组的行为,以及泛型提供的编译期的安全类型,

  1. //GenericArray ga = new GenericArray<Integer>(10);
  2. //ga.put(3, 10);
  3. //int abc = (Integer) ga.get(3);
  4. //Integer[] aaa = (Integer[]) ga.array(); //抛出ClassCastException
  5. class GenericArrayEx<T> {
  6. private T[] array;
  7. public GenericArray(int size) {
  8. array = (T[]) new Object[size];
  9. }
  10.  
  11. public void put(int index, T item) {
  12. array[index] = item;
  13. }
  14.  
  15. public T get(int index) {
  16. return array[index];
  17. }
  18.  
  19. public T[] array() {
  20. return array;
  21. }
  22. }

对于以上代码。我们採用一个GenericArray的类进行包装,但内部实际还是一个Object[]的对象数组,在put和get的时候获得了编译期间的检查。但问题来了,假设我们使用array()方法企图获得内部数组并转型的时候,会抛出ClassCastException,这是因为数组实际还是Object[]对象!为了解决问题,我们能够使用Array.newInstance。

  1. //GenericArrayEx ga = new GenericArrayEx<Integer>(Integer.class, 10);
  2. //ga.put(3, 10);
  3. //int abc = (Integer) ga.get(3);
  4. //Integer[] aaa = (Integer[]) ga.array(); //能够成功转型
  5. class GenericArrayEx<T> {
  6. private T[] array;
  7. public GenericArrayEx(Class<T> type, int size) {
  8. array = (T[]) Array.newInstance(type, size);
  9. }
  10.  
  11. public void put(int index, T item) {
  12. array[index] = item;
  13. }
  14.  
  15. public T get(int index) {
  16. return array[index];
  17. }
  18.  
  19. public T[] array() {
  20. return array;
  21. }
  22. }

这样,就能够使用T[]了。

Java泛型的一些限制的更多相关文章

  1. Java泛型的历史

    为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...

  2. 浅析Java 泛型

    泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...

  3. Java:泛型基础

    泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...

  4. java泛型基础

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Ja ...

  5. 使用java泛型设计通用方法

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...

  6. 关于Java泛型的使用

    在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Wind ...

  7. 初识java泛型

    1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...

  8. 【Java心得总结四】Java泛型下——万恶的擦除

    一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...

  9. 【Java心得总结三】Java泛型上——初识泛型

    一.函数参数与泛型比较 泛型(generics),从字面的意思理解就是泛化的类型,即参数化类型.泛型的作用是什么,这里与函数参数做一个比较: 无参数的函数: public int[] newIntAr ...

  10. 初识Java泛型以及桥接方法

    泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...

随机推荐

  1. HTML5练习4

    1.菜单条 主要代码 <!doctype html> <html> <head> <meta charset="utf-8"> &l ...

  2. 【LOJ】#2479. 「九省联考 2018」制胡窜

    题解 老了,国赛之前敲一个后缀树上LCT和线段树都休闲的很 现在后缀树上线段树合并差点把我写死 主要思路就是后缀树+线段树合并+容斥,我相信熟练的OIer看到这已经会了 但就是不想写 但是由于我过于老 ...

  3. Zookeeper Canary

    ZooKeeper Canary我理解用于测试ZK节点是否正常的心跳服务,这是从ClouderaManager中粘下来的: 这是 ZooKeeper 服务级运行状况测试,用于检查基本客户端操作是否正常 ...

  4. LOOPS 概率dp

    题意:迷宫是一个R*C的布局,每个格子中给出停留在原地,往右走一个,往下走一格的概率,起点在(1,1),终点在(R,C),每走一格消耗两点能量,求出最后所需要的能量期望 简单概率dp 注意   原地不 ...

  5. php 导入excel文件

    excel.php <?phprequire_once 'PHPExcel/PHPExcel.php';require_once 'PHPExcel/PHPExcel/IOFactory.php ...

  6. 给虚拟机下面的ubuntu系统增加硬盘存储空间

    给虚拟机下面的ubuntu系统增加硬盘存储空间   由于ubuntu系统是安装在vsphere上面的,所以可能会和vmware上面的有一点区别,打开exsi系统的配置页面,如下图所示. 选择添加存储器 ...

  7. 002.KVM环境部署

    一 环境准备 1.1 查看是否支持虚拟化 [root@kvm-host ~]# grep -E 'vmx|svm' /proc/cpuinfo 注意:intel为vmx,amd为svm. 1.2 确定 ...

  8. HDU 1402 A * B Problem Plus 快速傅里叶变换 FFT 多项式

    http://acm.hdu.edu.cn/showproblem.php?pid=1402 快速傅里叶变换优化的高精度乘法. https://blog.csdn.net/ggn_2015/artic ...

  9. bzoj1151 动物园

    Description 新建的圆形动物园是亚太地区的骄傲.圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围栏里有一 种动物.如下图所示: 你是动物园的公共主管.你要做的是,让每个来动物园的人 ...

  10. ELASTIC的备份与恢复

    前言 elasticsearch官方并没有提供合适的备份工具,然而生产场景中备份却是的确需要的. 本文介绍了使用自己写的php脚本以及第三方工具来进行索引的备份,恢复以及删除等操作. 全量备份 ela ...