- 浏览: 331910 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
xuanyuanxiaoxue:
...
Android - LayoutInflater -
柴兴博:
不错 多谢
Android 悬浮Activity并可拖动(访悬浮歌词) -
di1984HIT:
写的很好,我收藏一下。
java之动态代理模式(JDK和cglib) -
chinacssnj:
待测试,明天测,测试的结果发给大家
网络开发上传文件到服务器 -
fx_199182:
...
Android之MediaPlayer
Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter)。声明的类型参数在使用时用具体的类型来替换。泛型最主要的应用是在JDK 5中的新集合类框架中。对于泛型概念的引入,开发社区的观点是褒贬不一。
从好的方面来说,泛型的引入可以解决之前的集合类框架在使用过程中通常会出现的运行时刻类型错误,因为编译器可以在编译时刻就发现很多明显的错 误。而从不好的地方来说,为了保证与旧有版本的兼容性,Java泛型的实现上存在着一些不够优雅的地方。当然这也是任何有历史的编程语言所需要承担的历史 包袱。后续的版本更新会为早期的设计缺陷所累。
开发人员在使用泛型的时候,很容易根据自己的直觉而犯一些错误。比如一个方法如果接收ListObject作为形式参数,那么如果尝试将一个 ListString的对象作为实际参数传进去,却发现无法通过编译。虽然从直觉上来说,Object是String的父类,这种类型转换应该是合理的。 但是实际上这会产生隐含的类型转换问题,因此编译器直接就禁止这样的行为。本文试图对Java泛型做一个概括性的说明。
类型擦除
正确理解泛型概念的首要前提是理解类型擦除(type erasure)。 Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译 器在编译的时候去掉。这个过程就称为类型擦除。如在代码中定义的ListObject和ListString等类型,在编译之后都会变成List。JVM 看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻 出现类型转换异常的情况。类型擦除也是Java的泛型实现方式与C++模板机制实现方式之间的重要区别。
很多泛型的奇怪特性都与这个类型擦除的存在有关,包括:
- 泛型类并没有自己独有的Class类对象。比如并不存在ListString.class或是ListInteger.class,而只有List.class。
- 静态变量是被泛型类的所有实例所共享的。对于声明为MyClassT的类,访问其中的静态变量的方法仍然是 MyClass.myStaticVar。不管是通过new MyClassString还是new MyClassInteger创建的对象,都是共享一个静态变量。
- 泛型的类型参数不能用在Java异常处理的catch语句中。因为异常处理是由JVM在运行时刻来进行的。由于类型信息被擦除,JVM是无法区分 两个异常类型MyExceptionString和MyExceptionInteger的。对于JVM来说,它们都是 MyException类型的。也就无法执行与异常对应的catch语句。
类型擦除的基本过程也比较简单,首先是找到用来替换类型参数的具体类。这个具体类一般是Object。如果指定了类型参数的上界的话,则使用这 个上界。把代码中的类型参数都替换成具体的类。同时去掉出现的类型声明,即去掉的内容。比如T get()方法声明就变成了Object get();ListString就变成了List。接下来就可能需要生成一些桥接方法(bridge method)。这是由于擦除了类型之后的类可能缺少某些必须的方法。比如考虑下面的代码:
lass MyString implements ComparableString { public int compareTo(String str) { return 0; } }
当类型信息被擦除之后,上述类的声明变成了class MyString implements Comparable。但是这样的话,类MyString就会有编译错误,因为没有实现接口Comparable声明的int compareTo(Object)方法。这个时候就由编译器来动态生成这个方法。
实例分析
了解了类型擦除机制之后,就会明白编译器承担了全部的类型检查工作。编译器禁止某些泛型的使用方式,正是为了确保类型的安全性。以上面提到的ListObject和ListString为例来具体分析:
public void inspect(ListObject list) { for (Object obj : list) { System.out.println(obj); } list.add(1); //这个操作在当前方法的上下文是合法的。 } public void test() { ListString strs = new ArrayListString(); inspect(strs); //编译错误 }
这段代码中,inspect方法接受ListObject作为参数,当在test方法中试图传入ListString的时候,会出现编译错误。假设 这样的做法是允许的,那么在inspect方法就可以通过list.add(1)来向集合中添加一个数字。这样在test方法看来,其声明为 ListString的集合中却被添加了一个Integer类型的对象。这显然是违反类型安全的原则的,在某个时候肯定会抛出 ClassCastException。因此,编译器禁止这样的行为。编译器会尽可能的检查可能存在的类型安全问题。对于确定是违反相关原则的地方,会给 出编译错误。当编译器无法判断类型的使用是否正确的时候,会给出警告信息。
通配符与上下界
在使用泛型类的时候,既可以指定一个具体的类型,如ListString就声明了具体的类型是String;也可以用通配符?来表示未知类型, 如List?就声明了List中包含的元素类型是未知的。 通配符所代表的其实是一组类型,但具体的类型是未知的。List?所声明的就是所有类型都是可以的。但是List?并不等同于ListObject。 ListObject实际上确定了List中包含的是Object及其子类,在使用的时候都可以通过Object来进行引用。
而List?则其中所包含的元素类型是不确定。其中可能包含的是String,也可能是 Integer。如果它包含了String的话,往里面添加Integer类型的元素就是错误的。正因为类型未知,就不能通过new ArrayList?()的方法来创建一个新的ArrayList对象。因为编译器无法知道具体的类型是什么。但是对于 List?中的元素确总是可以用Object来引用的,因为虽然类型未知,但肯定是Object及其子类。考虑下面的代码:
public void wildcard(List? list) { list.add(1);//编译错误 }
如上所示,试图对一个带通配符的泛型类进行操作的时候,总是会出现编译错误。其原因在于通配符所表示的类型是未知的。
因为对于List?中的元素只能用Object来引用,在有些情况下不是很方便。在这些情况下,可以使用上下界来限制未知类型的范围。 如List? extends Number说明List中可能包含的元素类型是Number及其子类。而List? super Number则说明List中包含的是Number及其父类。当引入了上界之后,在使用类型的时候就可以使用上界类中定义的方法。比如访问 List? extends Number的时候,就可以使用Number类的intValue等方法。
类型系统
在Java中,大家比较熟悉的是通过继承机制而产生的类型体系结构。比如String继承自Object。根据Liskov替换原则,子类是可 以替换父类的。当需要Object类的引用的时候,如果传入一个String对象是没有任何问题的。但是反过来的话,即用父类的引用替换子类引用的时候, 就需要进行强制类型转换。编译器并不能保证运行时刻这种转换一定是合法的。这种自动的子类替换父类的类型转换机制,对于数组也是适用的。 String[]可以替换Object[]。但是泛型的引入,对于这个类型系统产生了一定的影响。正如前面提到的ListString是不能替换掉 ListObject的。
引入泛型之后的类型系统增加了两个维度:一个是类型参数自身的继承体系结构,另外一个是泛型类或接口自身的继承体系结构。第一个指的是对于 ListString和ListObject这样的情况,类型参数String是继承自Object的。而第二种指的是 List接口继承自Collection接口。对于这个类型系统,有如下的一些规则:
- 相同类型参数的泛型类的关系取决于泛型类自身的继承体系结构。即ListString是CollectionString 的子类型,ListString可以替换CollectionString。这种情况也适用于带有上下界的类型声明。
- 当泛型类的类型声明中使用了通配符的时候, 其子类型可以在两个维度上分别展开。如对Collection? extends Number来说,其子类型可以在Collection这个维度上展开,即List? extends Number和Set? extends Number等;也可以在Number这个层次上展开,即CollectionDouble和 CollectionInteger等。如此循环下去,ArrayListLong和 HashSetDouble等也都算是Collection? extends Number的子类型。
- 如果泛型类中包含多个类型参数,则对于每个类型参数分别应用上面的规则。
理解了上面的规则之后,就可以很容易的修正实例分析中给出的代码了。只需要把ListObject改成List?即可。ListString是List?的子类型,因此传递参数时不会发生错误。
开发自己的泛型类
泛型类与一般的Java类基本相同,只是在类和接口定义上多出来了用声明的类型参数。一个类可以有多个类型参数,如 MyClassX, Y, Z。 每个类型参数在声明的时候可以指定上界。所声明的类型参数在Java类中可以像一般的类型一样作为方法的参数和返回值,或是作为域和局部变量的类型。但是 由于类型擦除机制,类型参数并不能用来创建对象或是作为静态变量的类型。考虑下面的泛型类中的正确和错误的用法。
class ClassTestX extends Number, Y, Z { private X x; private static Y y; //编译错误,不能用在静态变量中 public X getFirst() { //正确用法 return x; } public void wrong() { Z z = new Z(); //编译错误,不能创建对象 } }
最佳实践
在使用泛型的时候可以遵循一些基本的原则,从而避免一些常见的问题。
- 在代码中避免泛型类和原始类型的混用。比如ListString和List不应该共同使用。这样会产生一些编译器警告和潜在的运行时异常。当需要利用JDK 5之前开发的遗留代码,而不得不这么做时,也尽可能的隔离相关的代码。
- 在使用带通配符的泛型类的时候,需要明确通配符所代表的一组类型的概念。由于具体的类型是未知的,很多操作是不允许的。
- 泛型类最好不要同数组一块使用。你只能创建new List?[10]这样的数组,无法创建new ListString[10]这样的。这限制了数组的使用能力,而且会带来很多费解的问题。因此,当需要类似数组的功能时候,使用集合类即可。
- 不要忽视编译器给出的警告信息。
泛型之基础讲解请参考:http://www.cnblogs.com/panjun-Donet/archive/2008/09/27/1300609.html
摘自:http://news.cnblogs.com/n/93005/
发表评论
-
java clone技术 浅谈
2011-10-23 14:58 9221.java里的clone分为: A:浅复制(浅克隆): ... -
java synchronized详解
2011-10-23 10:31 753记下来,很重要。 Java语言的关键字,当它用来修饰一 ... -
Java 多线程同步 锁机制与synchronized
2011-10-21 17:25 1391打个比方:一个object就像一个大房子,大门永远打开。房子里 ... -
Java多线程编程总结(转载)
2011-10-21 16:54 754http://www.blogjava.net/cmzy/ar ... -
java内部类的总结
2011-10-15 14:42 707从Java1.1开始引入 ... -
java中的io系统详解
2011-10-10 11:26 739参考:http://expert.iteye.com/blog ... -
Java代码编写的30条建议
2011-10-10 10:22 760(1) 类名首字母应该大写 ... -
Java中局部内部类可以访问它所在方法中定义的final修饰的局部变量的合理解释
2011-09-20 11:21 1320标题有点长,可能有点 ... -
六种异常处理的陋习
2011-09-19 14:42 741你觉得自己是一个Java专 ... -
Java中常见的异常
2011-09-19 14:05 963Java 中异常的分类 所有异常,都继承自 ... -
Java异常的分类 .
2011-09-18 21:52 7911. 异常机制 异 ... -
java数组反射
2011-09-13 17:35 2082数组反射 如果因为某种原因,您并不确定参数或对象是不是数组, ... -
Java中反射机制详解
2011-09-13 14:53 1276问题: 在运行时,对一个JAVA类,能否知道属性和方 ... -
java枚举之EnumSet and EnumMap
2011-09-12 20:17 2638一:EnumSet import java.util.*; ... -
java中获取日期函数应用
2011-09-10 17:11 850(1)String类型转换成日期(Date类型) Sim ... -
java 时间格式化问题
2011-09-10 17:05 1000java 时间格式化问题 java.util.*; ... -
Java 集合篇
2011-09-07 18:51 7771. Java集合类库中最重要的两个接口Collec ... -
Comparable和Comparator接口
2011-09-06 13:13 764当需要排序的集合或数组不是单纯的数字型时,通常可以使用C ... -
Java对象初始化顺序
2011-09-06 10:56 1288前几天与fwb同学说起java笔试题,想起这个东西经常被考,重 ... -
全面接触Java集合框架
2011-09-05 23:33 887http://www.iteye.com/topic/1647 ...
相关推荐
类型擦除是Java泛型实现的关键机制之一。其主要过程包括: 1. **类型替换**:将泛型中的类型参数替换为具体的类型。如果没有指定具体的类型,则默认使用`Object`类型。如果有类型边界(上界),则使用该边界作为...
《Java深度历险》这本书是Java开发者的一本深入学习指南,它涵盖了Java编程语言的核心概念、高级特性以及实际开发中的应用技巧。通过本书,读者可以系统地了解Java的各个方面,从而提升自己的编程技能和问题解决能力...
《王森 Java深度历险》是一本专门为Java初学者精心编写的教材,旨在引领读者深入探索Java编程的世界。王森,作为业界知名的IT专家,以其丰富的教学经验和深厚的编程...现在,就让我们一起踏上这趟Java深度历险之旅吧!
《Java 深度历险》是一本专为Java开发者准备的深度学习书籍,它涵盖了Java编程语言的核心概念、高级特性以及实战应用。通过这本书,读者可以深入理解Java的内部机制,提升编程技能,实现从初级到高级的跨越。下面...
《Java深度历险》这本书主要探讨了Java编程语言的深度知识,涵盖了从早期版本到Java 2 SDK的演进历程。Java是由Sun Microsystems开发的一种高级编程语言,最初被称为OAK,后来发展为Java 1.0,并逐步演变为Java 1.1...
《Java深度历险》是一本面向已有一定Java基础的学习者,旨在深化理解并提升Java编程技能的专业书籍。作者王森,以其丰富的编程经验和深入的理解,为读者揭示了Java语言的精髓与复杂性,帮助程序员从初级阶段跨越到...
《JAVA2深度历险_简体版》是一本专注于Java编程技术的深度探索书籍,旨在帮助读者深入理解和掌握Java语言的各个方面。这本书以其简体版的形式,相较于繁体版更便于国内读者阅读和理解,降低了学习Java技术的语言障碍...
《Java深度历险》这本书是为Java开发初学者量身打造的一本技术指南,旨在帮助读者深入理解Java语言的核心概念和机制,从而更好地掌握编程技能。以下是对书中的关键知识点的详细阐述: 1. **Java基础语法**:Java的...
《Java深度历险》这一主题涵盖了Java编程语言的高级特性和深入理解,旨在帮助开发者们提升他们的Java技术能力。从给定的文件名来看,我们可以期待这些PDF文档包含了一些关于Java架构设计和进阶探索的内容。 1. **...
《Java深度历险》文档是一份详尽的Java编程学习资料,旨在帮助读者深入理解Java语言的核心概念、机制以及在实际开发中的应用。通过这份文档,你可以系统地探索Java的世界,提升自己的编程技能。 首先,Java深度历险...
《Java深度历险》是一本全面探讨Java编程技术的书籍,涵盖了从基础到高级的各种主题。这个RAR压缩包很可能是该书的电子版资源,包括PDF文档、代码示例或其他辅助学习材料。以下是对Java深度历险中可能涉及的一些关键...
《JAVA2深度历险》是一本深入探讨Java编程语言内部机制的书籍,旨在帮助开发者从底层理解并掌握Java技术。本书覆盖了Java的核心概念、工具、框架以及虚拟机(JVM)的工作原理,旨在提升读者的编程技能和问题解决能力...
java深度历险 InfoQ中文站 1、java字节码操作 2、java类的加载、链接和初始化 3、java线程 4、java垃圾回收机制与引用类型 5、java泛型 6、java注解 7、java反射与动态代理 8、javaI/O 9、java安全 10、java对象序列...
《JAVA深度历险》这本书是Java开发者的一本深入学习指南,它旨在揭示Java语言的内在机制和高级特性,帮助读者从底层理解Java的工作原理。在Java编程的世界里,深度理解和熟练掌握这些知识点对于提升开发效率、优化...
《Java模式:Java深度历险》是一本专为Java开发者设计的深度学习书籍,它深入探讨了Java编程中的各种设计模式和技术。这本书的核心目标是帮助读者理解和应用在实际项目中广泛使用的模式,以提高代码质量和可维护性。...
《Java深度历险》这本书是Java开发者进阶的宝贵资源,它涵盖了Java编程中的许多核心概念和技术,旨在帮助读者深入理解这门强大的编程语言。在解压后的文件中,我们可以期待找到一系列章节或教程,详细讲解Java的各个...
《Java深度历险》这本书是Java开发者们探索技术深度的重要指南。它涵盖了Java语言的核心概念、高级特性以及实际开发中的应用技巧,旨在帮助读者深入理解Java的内在机制,提升编程能力。以下是一些主要的知识点: 1....
Java深度历险,这是一次探索Java编程语言的深度之旅,涵盖了从基础知识到高级特性的全方位解析。在Java的世界里,深度探险意味着我们要深入理解其内部机制,掌握那些能够提升编程效率、优化程序性能的关键知识点。 ...
《Java深度历险:实例教您运用Java》是一本旨在帮助读者深入理解并熟练掌握Java编程语言的实战型教程。本书以丰富的实例为引领,旨在解决开发者在实际开发过程中可能遇到的各种难题,让读者能够在实践中不断提升Java...