Java泛型详解
来源:互联网 发布:java api接口测试工具 编辑:程序博客网 时间:2024/05/01 23:55
Java泛型详解 原作者:火木棉 博客地址:网易博客
一、类型擦除
正确理解泛型概念的首要前提是理解类型擦除(type erasure)。 Java中的泛型基本上都是在编译器这个层次来实现的。在生成的很多泛型的奇怪特性都与这个类型擦除的存在有关,包括:
- 泛型类并没有自己独有的Class类对象。
比如并不存在List<String>. class或是List<Integer>.class, 而只有List.class。 - 静态变量是被泛型类的所有实例所共享的。
对于声明为MyClass<T>的类, 访问其中的静态变量的方法仍然是 MyClass.myStaticVar。不管是通过new MyClass<String>还是new MyClass<Integer>创建的对象, 都是共享一个静态变量。 - 泛型的类型参数不能用在Java异常处理的catch语句中。
因为异常处理是由JVM在运行时刻来进行的。 由于类型信息被擦除, JVM是无法区分两个异常类型MyException< String>和MyException<Integer>的。 对于JVM来说,它们都是 MyException类型的。 也就无法执行与异常对应的catch语句。
类型擦除的基本过程也比较简单,
class MyString implements Comparable<String>{ public int compareTo(String str){ return 0; }}当类型信息被擦除之后,上述类的声明变成了class MyString implements Comparable。但是这样的话,
二、实例分析
了解了类型擦除机制之后,
public void inspect(List<Object> list) { for (Object obj : list) { System.out.println(obj); } list.add(1); //这个操作在当前方法的上下文是合法的。 } public void test() { List<String> strs = new ArrayList<String>(); inspect(strs); //编译错误 }
这段代码中,inspect方法接受List<Object>
三、通配符(?)与上下界(extends ,super )
在使用泛型类的时候,既可以指定一个具体的类型,如List<
package com.codeleven.test;import java.util.ArrayList;import java.util.Arrays;import java.util.List;public class Main{public static void test1(List<?> list){//list.add(new Integer(10)); 不能进行编译,因为list这个引用是某个未知的具体类;如果?代表String,那怎么添加Integer?//list.add("123"); 如果?代表Integer,那怎么添加String? Integer aint= (Integer)list.get(0);String astr = (String)list.get(1);}public static void test2(List<? extends Number> list){//list.add(new Integer(1)); 因为list的具体类型是继承Number的一个子类,不过究竟是Integer还是Float还是...无从得知,在编译期就直接报错;//list.add(new Float(1.3)); //假设没有编译期的报错,那么因为上界是Number的子类,所以我们可以自由添加Float,Integer,Double等等类型,但是到了运行期,真正的类型Integer被检测出来,此时依旧会报ClassCastExceptionNumber temp1 = list.get(0); //可以发现获取到的类型直接是Number, 所以限定了上界,那么获取出来的类型必定是Number或者Number的子类Number temp2 = list.get(1);}public static void test3(List<? super Number> list){list.add(new Integer(567)); //因为限定了下界,所有再加入的类型都一定会是Number的子类或Number,所以用Number接受就可以了//list.add(new String("123"));报错,因为不是Number的子类//Number temp = list.get(0); 编译器不知道取出来的究竟是Number或者Number的某个具体父类}public static void main(String[] args){//通配符的使用和解释List<?> alist = new ArrayList<Object>(Arrays.asList(new Integer(1), new String("123")));test1(alist);//上界List<? extends Number> nlist = new ArrayList<Integer>(Arrays.asList(new Integer(123), new Integer(111)));test2(nlist);//下界List<? super Number> slist = new ArrayList<Object>(Arrays.asList(new Integer(123), new Integer(999), new String("哈哈")));test3(slist);}}
如上所示,试图对一个带通配符的泛型类进行操作的时候,
因为对于List<?>中的元素只能用Object来引用,
四、类型系统
在Java中,引入泛型之后的类型系统增加了两个维度:
- 相同类型参数的泛型类的关系取决于泛型类自身的继承体系结构。
即List<String>是Collection< String> 的子类型,List<String> 可以替换Collection<String>。 这种情况也适用于带有上下界的类型声明。 - 当泛型类的类型声明中使用了通配符的时候, 其子类型可以在两个维度上分别展开。如对Collection<
? extends Number>来说, 其子类型可以在Collection这个维度上展开, 即List<? extends Number>和Set<? extends Number>等;也可以在Number这个层次上展开, 即Collection<Double>和 Collection<Integer>等。如此循环下去, ArrayList<Long>和 HashSet<Double> 等也都算是Collection<? extends Number>的子类型。 - 如果泛型类中包含多个类型参数,
则对于每个类型参数分别应用上面的规则。
五、开发自己的泛型类
泛型类与一般的Java类基本相同,只是在类和接口定义上多出来
class ClassTest<X extends Number, Y, Z> { private X x; private static Y y; //编译错误,不能用在静态变量中 public X getFirst() { //正确用法 return x; } public void wrong() { Z z = new Z(); //编译错误,不能创建对象 ,因为泛型类并没有自己独立的Class类对象 } }
End、最佳实践
在使用泛型的时候可以遵循一些基本的原则,- 在代码中避免泛型类和原始类型的混用。比如List<
String>和List不应该共同使用。 这样会产生一些编译器警告和潜在的运行时异常。当需要利用JDK 5之前开发的遗留代码,而不得不这么做时, 也尽可能的隔离相关的代码。 - 在使用带通配符的泛型类的时候,
需要明确通配符所代表的一组类型的概念 。由于具体的类型是未知的,很多操作是不允许的。 - 泛型类最好不要同数组一块使用。你只能创建new List<?>[10]这样的数组,无法创建new List<String>[10]这样的。
这限制了数组的使用能力,而且会带来很多费解的问题。因此, 当需要类似数组的功能时候,使用集合类即可。 - 不要忽视编译器给出的警告信息。
参考资料
- Generics gotchas
- Java Generics FAQs
- Generics in Java Programming Language
- Java泛型详解
- java泛型详解
- java泛型详解
- Java泛型详解
- Java泛型详解
- java泛型详解
- Java泛型详解
- java泛型详解
- java 泛型详解
- java 泛型详解
- Java 泛型详解
- java 泛型详解
- java 泛型详解
- java泛型详解
- java 泛型详解
- Java泛型详解
- java 泛型详解
- java 泛型详解
- mysql 权限
- tomcat配置日志存放地址
- 冒泡排序(C++)
- 浏览器url地址怎样转换为本地正常url
- 水波灵纹
- Java泛型详解
- 解决新版AndroidStudio 导入HttpClient冲突
- iOS监听模式系列之通知中心
- 【HTML笔记一】HTML介绍
- 模式识别(Pattern Recognition)学习笔记(十九)--多层感知器模型(MLP)
- 编程之美:水王问题及扩展
- 深入了解Android自动化测试-1.monkey介绍
- 柴俊理金:零售疲软支撑金银,供应吃紧提振原油
- debug(2) 连接的时候一直断开、重连