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 ...
随机推荐
- 【PAT】1103 Integer Factorization(30 分)
The K−P factorization of a positive integer N is to write N as the sum of the P-th power of K positi ...
- 001.DNS原理及配置格式
一 dns简介 DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串. ...
- SpringAOP实战应用
Springboot中使用AOP特性非常简单,使用@AspectJ注解,然后再配置中开启AspectJ即可.在日常的应用,有时可以将日志记录和异常处理在一个拦截器中统一处理,但有时在项目中无法通过一个 ...
- python scrapy 调试模式
scrapy通过命令行创建工程,通过命令行启动爬虫,那么有没有方式可以在IDE中调试我们的爬虫呢? 实际上,scrapy是提供给我们工具的, 1. 首先在工程目录下新建一个脚本文件,作为我们执行爬虫的 ...
- 1,EasyNetQ-链接到RabbitMQ
一.链接到RabbitMQ 1,创建连接 注意不能有空格 var bus = RabbitHutch.CreateBus(“host=myServer;virtualHost=myVirtualHos ...
- python 修改文件中的内容
在python的文件操作中,是没有办法对文件中具体某行或者某个位置的内容进行局部的修改的,如果需要对文件的某一行内容进行修改,可以先将文件中的所有的内容全部读取出来,再进行内容判断,是否是需要修改的内 ...
- android studio 查看大纲
就是 structure 面板 快捷键 Alt+7 === android studio 查看方法说明 点击菜单“View”-“Quick Documentation" 建议直接查看源代码文 ...
- NOI.AC NOIP模拟赛 第二场 补记
NOI.AC NOIP模拟赛 第二场 补记 palindrome 题目大意: 同[CEOI2017]Palindromic Partitions string 同[TC11326]Impossible ...
- [CC-FNCS]Chef and Churu
[CC-FNCS]Chef and Churu 题目大意: 一个长度为\(n(n\le10^5)\)的数列\(A_{1\sim n}\),另有\(n\)个函数,第\(i\)个函数会返回数组中标号在\( ...
- npm 升级自身
用cue-cli 生成新项目 提示升级npm 解决方案: npm install -g npm 呵呵呵,简直太简单了 然而今天是2016.11.11