在 Java 中有效地使用泛型,一定要注意以下限制:
不能使用原始数据类型实例化泛型类
考虑下面的泛型类:
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
// ...
}
在创建 Pair 对象的时候,类型参数 K 和 V 不能是原始数据类型:
Pair<int, char> p = new Pair<>(8, 'a'); // 编译错误
类型参数 K 和 V 只能使用非原始数据类型:
Pair<Integer, Character> p = new Pair<>(8, 'a');
Java 编译器会像下面这样使用 Integer.valueOf(8) 自动封装 8,使用 Character('a') 自动封装 'a':
Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));
不能创建类型参数实例
不能创建类型参数的实例,下面这段代码会出现编译错误:
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
为了规避这个问题,你可以使用反射机制:
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}
现在可以像下面代码这样来调用 append 方法:
List<String> ls = new ArrayList<>();
append(ls, String.class);
不能使用类型参数声明静态属性
类的静态属性是类级别的变量,被所有非静态对象共享。因此,不能使用类型参数声明静态属性。
考虑下面的代码:
public class MobileDevice<T> {
private static T os;
// ...
}
如果允许类型参数声明静态属性,那么下面的代码将会很混乱:
MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();
因为静态属性 os 同时被 phone, pager, 和 pc 共享,那么现在 os 的真实类型是什么?它不可能同时是 Smartphone, Pager, 和 TabletPC 类型。因此,不允许声明静态的类型参数属性。
不能对泛型类使用强制类型转换和 instanceof
因为 Java 编译器在编译期会对所有泛型进行类型清除操作,因此,在运行时不能确定使用的是哪个类型的类型参数。
public static <E> void rtti(List<E> list) {
if (list instanceof ArrayList<Integer>) { // 编译错误
// ...
}
}
假如传递给 rtti 方法的 list 参数中的值如下:
{ ArrayList<Integer>, ArrayList<String> LinkedList<Character>, ... }
运行时不会跟踪类型参数,因此也无法区分 ArrayList<Integer> 和 ArrayList<String> 的不同。你能做的最多是使用无限制的通配符来确保类型是 ArrayList:
public static void rtti(List<?> list) {
if (list instanceof ArrayList<?>) { // OK; instanceof requires a reifiable type
// ...
}
}
通常情况下,除非使用了无限制的通配符,否则泛型类不能进行类型强制转换:
List<Integer> li = new ArrayList<>();
List<Number> ln = (List<Number>) li; // 编译错误
但是,在有的时候,如果编译器能确认类型参数是正确的情况下,可以进行类型强制转换:
List<String> l1 = ...;
ArrayList<String> l2 = (ArrayList<String>)l1; // OK
不能创建泛型类的数组
你不能创建泛型类的数组,例如,下面的代码将不能通过编译:
List<Integer>[] arrayOfLists = new List<Integer>[2]; // 编译错误
下面的代码演示了为什么会发生这个错误:
Object[] strings = new String[2];
strings[0] = "hi"; // OK
strings[1] = 100; // An ArrayStoreException is thrown.
那么如果是泛型类 List 的数组,同样会有这个问题:
Object[] stringLists = new List<String>[]; // 编译错误,但是我们假装可以这么做
stringLists[0] = new ArrayList<String>(); // OK
stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown
不能创建、捕获或抛出类型参数的对象
泛型类不能直接或间接继承 Throwable 类,例如,下面的代码不能通过编译:
class MathException<T> extends Exception { /* ... */ } // 编译错误
class QueueFullException<T> extends Throwable { /* ... */ // 编译错误
方法中也不能捕获类型参数异常:
public static <T extends Exception, J> void execute(List<J> jobs) {
try {
for (J job : jobs)
// ...
} catch (T e) { // 编译错误
// ...
}
}
唯一能做的是,将类型参数放到方法的 throws 后面:
class Parser<T extends Exception> {
public void parse(File file) throws T { // OK
// ...
}
}
不允许仅仅是类型参数不同的情况下进行方法重载
下面这种写法将会发生编译错误:
public class Example {
public void print(Set<String> strSet) { }
public void print(Set<Integer> intSet) { }
}
文章来源:
http://www.aptusource.org/2014/04/restrictions-on-generics/
分享到:
相关推荐
主要介绍了Java泛型的使用限制,结合实例形式分析了不能使用java泛型的情况以及泛型使用的相关注意事项,需要的朋友可以参考下
详细的介绍了集合框架的用法,及其语法规则,剖析了使用的使用注意事项,帮助更牢靠的掌握集合框架的知识及泛型内容。谢谢
主要介绍了Java泛型定义与用法,结合实例形式较为详细的分析了Java中泛型的概念、原理、定义、使用方法及相关操作注意事项,需要的朋友可以参考下
主要介绍了Java泛型类与泛型方法的定义,结合实例形式详细分析了java泛型类与泛型方法定义、用法及相关操作注意事项,需要的朋友可以参考下
创建您自己的泛型类时,需要特别注意以下事项: 将哪些类型通用化为类型参数。 通常,能够参数化的类型越多,代码就会变得越灵活,重用性就越好。但是,太多的通用化会使其他开发人员难以阅读或
主要介绍了Java定义泛型方法,结合实例形式分析了java定义泛型的相关操作技巧与注意事项,需要的朋友可以参考下
主要介绍了Java泛型定义与用法,结合实例形式分析了java泛型的功能、定义、应用场景及相关使用注意事项,需要的朋友可以参考下
泛型类与接口2.1 基本用法2.1.1 泛型的声明2.1.2 示例2.2 注意事项3. 泛型方法4. 泛型类型的继承规则5. 通配符类型5.1 没有限制的通配符5.2有限制的通配符 1. 泛型的用处 集合容器类在设计阶段/声明阶段不能确定这...
主要介绍了Java使用反射来获取泛型信息,结合实例形式分析了java基于反射操作泛型信息的相关实现技巧与注意事项,需要的朋友可以参考下
本文给大家汇总介绍了下java中的泛型的相关资料,包括引入泛型机制的原因,泛型类,泛型方法,泛型的实现以及泛型的注意事项,非常的详细,有需要的小伙伴可以参考下
C# 泛型数组学习中我们需要注意什么事项呢?C# 泛型数组的使用又是如何呢?那么本文就向你详细介绍这方面的内容
主要介绍了Java封装数组之改进为泛型数组操作,结合实例形式详细分析了Java封装数组为泛型数组相关原理、操作技巧与注意事项,需要的朋友可以参考下
14.1.3 匿名类型和隐式局部变量的更多注意事项 388 14.2 集合初始化器 390 14.3 是什么使类成为集合:IEnumerable 392 14.3.1 foreach和数组 392 14.3.2 foreach和IEnumerable 393 14.3.3 ...
所属命名空间:System.Collections.Generic public class List<T> : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable List类是 ArrayList 类的泛型...性能注意事项: 在决定使用IList<T> 还是使
源码描述: 一、源码特点 1、三层架构MVC通用网站CMS系统源码,网站前端使用js、jqury、Html5、bootstrap响应式布局...三、注意事项 1、开发环境为Visual Studio 2013,数据库为SqlServer2008R2,使用.net 4.5开发。
· 使用泛型和接口来定义可重用的算法 · 高效使用特定的CLR类型——委托、枚举、定制attribute、数组和字符串 · 理解垃圾回收器是如何管理内存资源的 · 使用线程池、任务、取消、计时器和异步I/O操作来设计响应性...
NCo3.0调用RFC,通用接口, 支持泛型和动态类型。 Sap通用接口 ...注意事项: 1. 仅对属性赋值,字段自动忽略(如果有异常,请检查) 2. 属性不能多于sap接口的参数 3. 属性名即是sap接口的Key 列如:
比如,switch的空指针问题、浮点数的比较、无泛型限制引起的类型混乱、加锁与解锁的注意事项、YYYY的日期格式问题等; 2.修改描述112处。比如,IFNULL的判断方式、集合的toArray的数组长度、日志占位符的处理等; ...
比如,switch的空指针问题、浮点数的比较、无泛型限制引起的类型混乱、加锁与解锁的注意事项、YYYY的日期格式问题等; 2.修改描述112处。比如,IFNULL的判断方式、集合的toArray的数组长度、日志占位符的处理等; ...
14.6. 使用互斥锁的注意事项 15. 十四 标准I/O流与文件 15.1. 对文件的操作 15.2. 处理跨平台性 15.3. 对象的序列化接口 15.4. I/O流基础 15.5. 流的分类 15.6. I/O输入输出 16. 十五 网络编程 16.1. ...