分享

Java泛型笔记

 醉三郎 2012-05-29

定义
Java的类属机制,即类型参数化

语法
类型参数化

Java代码 复制代码 收藏代码
  1. class GenericClass<T> { }   
  2. interface GenericInterface<T> { }   
  3. <T> T genericFunction(T args…) { }  

 
类型实例化

Java代码 复制代码 收藏代码
  1. SubGenericClass extends GenericClass<String>   
  2. new GenericClass<String>   
  3. genericFunction(new String(“Hello World”))  

 

目的
为模板代码在编译器级别避免产生ClassCastException
如果没有泛型,那么在定义模板代码时只能将类型不确定的引用声明为可能类型的公共基类,离开模板代码后必须手动向下转型,存在潜在的产生ClassCastException可能性
泛型要求在进入泛型代码前指定一个实例类型以替换类型参数,由编译器在离开后自动向下转型为实例类型,从而防止手动向下转型可能出现的错误,避免产生ClassCastException

原理
Java泛型的实现原理是擦除
擦除是指在泛型代码内部,用类型参数声明的引用均视为Object类型,因此只能调用Object的方法,所有实例类型的相关信息都将消失

 

Java采取擦除的策略是为了兼容Java1.5以前的应用
泛型的作用只体现在进入泛型代码时编译器检查对象是否为实例类型或其后代类,在离开泛型代码时编译器自动将对象向下转型为实例类型,并不代表泛型可以在泛型代码内部得到实例类型的信息
由于擦除的存在,Generic<T>和Generic<S>是相同的

限制
(“外露”类型参数 ― 单独出现而不是位于某个类型中的类型参数)
1. 不应在静态成员中引用封闭类型参数
静态成员属于这个类所有对象共有,而泛型类的不同对象的实例参数可能不同
2. 不能用基本类型实例化泛型类型参数
基本类型(int等)不是Object的子类,应用包装类(Integer等)代替
3. 不能在数据类型转换或 instanceof 操作中使用“外露”类型参数
instanceof是静态操作,而在泛型代码内部没有任何关于实例类型的信息,应用isInstance()代替

(不太理解其中的道理,什么是静态操作?)
4. 不能在 new 操作中使用“外露”类型参数
不能确定实例类型的构造器有哪些
5. 不能在类定义的 implements 或 extends 子句中使用“外露”类型参数
防止子类(或实现) 的对象的实例类型与基类(或接口)的应用的实例类型不一致导致的向上转型出错

受限泛型
只能在定义时使用
用extends指定了上界的泛型,用于限定合法实例类型的范围,如果没有指定,默认为Object
<T extends SomeClass> 实例类型必须是SomeClass的子类
<T extends Generic<T>> 实例类型必须是Generic的子类,并且Generic的类型参数也被实体化为这个类型
Generic <T extends Generic<T>> 实例类型必须是正在定义的这个类的子类
无论是在一般泛型代码还是受限泛型代码中用类型参数声明的引用均视为Object类型,但在一般泛型代码中,任何类型均可实例化类型参数,因此对引用任何的向下类型转换都是不安全的;而是在受限泛型代码中,只有上界或其后代类型可以实例化类型参数,对引用可以安全的向下转型为上界类型或其祖先类型

通配符
只能在声明时使用
用于扩大实例化的泛型引用所能引用的泛型对象

Java代码 复制代码 收藏代码
  1. class Generic <T> {   
  2. T t;   
  3. set(T t) {this.t = t;}   
  4. T get() {return this.t;}   
  5. }   
  6. class Food {}   
  7. class Fruit extends Food{}   
  8. class Apple extends Fruit {}   
  9. class Orange extends Fruit {}   
  10. Generic<Fruit> fruit;   
  11. Generic<Apple> apple = new Generic<Apple>();   
  12. Generic<Orange> orange = new Generic<Orange>();  

 
在Java泛型中,引用fruit不能引用apple、orange,只能使用通配符来完成这个功能
上界
用extends指定上界,使引用可以引用用上界类型或其后代类型实例化的对象,进入方法不能调用,开方法返回上界类型

Java代码 复制代码 收藏代码
  1. Generic<? extends Fruit> fruit1;  

 
此时,fruit1可以引用apple、orange,

Java代码 复制代码 收藏代码
  1. fruit1.set()  

 
不能调用,假设可以调用,下面代码将会破坏泛型机制

Java代码 复制代码 收藏代码
  1. fruit1 = apple;   
  2. fruit1.set(new Orange);   
  3. Apple otherApple = apple.get();  

 
此时fruit1和apple引用同一对象,Apple otherApple = apple.get()将一个Orange的对象向下转型为Apple,产生ClassCastException

Java代码 复制代码 收藏代码
  1. fruit1.get()  

 
返回Fruit类型的对象
下界
用super指定上界,使引用可以引用用下界类型或其先祖类型实例化的对象,进入方法参数类似是下界类型或其后代类型,离开方法返回Object对象

Java代码 复制代码 收藏代码
  1. Generic<? super Fruit> fruit2;   
  2. fruit2 = new Generic<Food>();   
  3. fruit2.set()  

 
参数类型可以是Fruit或其后代类型

Java代码 复制代码 收藏代码
  1. fruit2.get()  

 
返回Object对象

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多