`

jdk1.5-新特性之泛型

    博客分类:
  • java
F# 
阅读更多
java泛型
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
介绍
  在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
  泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
编辑本段规则和限制
  1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
  2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
  3、泛型的类型参数可以有多个。
  4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
  5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");
  泛型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。在此给出我曾经 了解泛型时候写出的两个例子(根据看的印象写的),实现同样的功能,一个使用了泛型,一个没有使用,通过对比,可以很快学会泛型的应用,学会这个基本上学 会了泛型70%的内容。

  
例子一:使用了泛型 
public class Gen<T> { 
  private T ob; //定义泛型成员变量 
  public Gen(T ob) { 
  this.ob = ob; 
  } 
  public T getOb() { 
  return ob; 
  } 
  public void setOb(T ob) { 
  this.ob = ob; 
  } 
  public void showType() { 
  System.out.println("T的实际类型是: " + ob.getClass().getName()); 
  } 
  } 
  public class GenDemo { 
  public static void main(String[] args){ 
  //定义泛型类Gen的一个Integer版本 
  Gen<Integer> intOb=new Gen<Integer>(88); 
  intOb.showType(); 
  int i= intOb.getOb(); 
  System.out.println("value= " + i); 
  System.out.println("----------------------------------"); 
  //定义泛型类Gen的一个String版本 
  Gen<String> strOb=new Gen<String>("Hello Gen!"); 
  strOb.showType(); 
  String s=strOb.getOb(); 
  System.out.println("value= " + s); 
  } 
  } 
  例子二:没有使用泛型 
  public class Gen2 { 
  private Object ob; //定义一个通用类型成员 
  public Gen2(Object ob) { 
  this.ob = ob; 
  } 
  public Object getOb() { 
  return ob; 
  } 
  public void setOb(Object ob) { 
  this.ob = ob; 
  } 
  public void showTyep() { 
  System.out.println("T的实际类型是: " + ob.getClass().getName()); 
  } 
  } 
  public class GenDemo2 { 
  public static void main(String[] args) { 
  //定义类Gen2的一个Integer版本 
  Gen2 intOb = new Gen2(new Integer(88)); 
  intOb.showTyep(); 
  int i = (Integer) intOb.getOb(); //需要显式强转
  System.out.println("value= " + i); 
  System.out.println("---------------------------------"); 
  //定义类Gen2的一个String版本 
  Gen2 strOb = new Gen2("Hello Gen!"); 
  strOb.showTyep(); 
  String s = (String) strOb.getOb();//需要显式强转
  System.out.println("value= " + s); 
  } 
  } 
  运行结果: 
  两个例子运行Demo结果是相同的,控制台输出结果如下: 
  T的实际类型是: 
  java.lang.Integer 
  value= 88 
  ---------------------------------- 
  T的实际类型是: java.lang.String 
  value= Hello Gen! 
  Process finished with exit code 0 
  看明白这个,以后基本的泛型应用和代码阅读就不成问题了。
编辑本段逐渐深入泛型
1、没有任何重构的原始代码
  有两个类如下,要构造两个类的对象,并打印出各自的成员x。 
  public class StringFoo { 
  private String x; 
  public StringFoo(String x) { 
  this.x = x; 
  } 
  public String getX() { 
  return x; 
  } 
  public void setX(String x) { 
  this.x = x; 
  } 
  } 
  public class DoubleFoo { 
  private Double x; 
  public DoubleFoo(Double x) { 
  this.x = x; 
  } 
  public Double getX() { 
  return x; 
  } 
  public void setX(Double x) { 
  this.x = x; 
  } 
  } 
  以上的代码实在无聊,就不写如何实现了。
2、对上面的两个类进行重构,写成一个类
  因为上面的类中,成员和方法的逻辑都一样,就是类型不一样,因此考虑重构。Object是所有类的父类,因此可以考虑用Object做为成员类型,这样就可以实现通用了,实际上就是“Object泛型”,暂时这么称呼。 
  public class ObjectFoo { 
  private Object x; 
  public ObjectFoo(Object x) { 
  this.x = x; 
  } 
  public Object getX() { 
  return x; 
  } 
  public void setX(Object x) { 
  this.x = x; 
  } 
  } 
  写出Demo方法如下: 
  public class ObjectFooDemo { 
  public static void main(String args[]) { 
  ObjectFoo strFoo = new ObjectFoo("Hello Generics!"); 
  ObjectFoo douFoo = new ObjectFoo(new Double("33")); 
  ObjectFoo objFoo = new ObjectFoo(new Object()); 
  System.out.println("strFoo.getX="+(String)strFoo.getX()); 
  System.out.println("douFoo.getX="+(Double)douFoo.getX()); 
  System.out.println("objFoo.getX="+(Object)objFoo.getX()); 
  } 
  } 
  运行结果如下: 
  strFoo.getX=Hello Generics! 
  douFoo.getX=33.0 
  objFoo.getX=java.lang.Object@19821f 


  解说:在Java 5之前,为了让类有通用性,往往将参数类型、返回类型设置为Object类型,当获取这些返回类型来使用时候,必须将其“强制”转换为原有的类型或者接口,然后才可以调用对象上的方法。
3、Java1.5泛型来实现
   强制类型转换很麻烦,我还要事先知道各个Object具体类型是什么,才能做出正确转换。否则,要是转换的类型不对,比如将“Hello Generics!”字符串强制转换为Double,那么编译的时候不会报错,可是运行的时候就挂了。那有没有不强制转换的办法----有,改用 Java5泛型来实现。

  public class GenericsFoo<T> { 
  private T x; 
  public GenericsFoo(T x) { 
  this.x = x; 
  } 
  public T getX() { 
  return x; 
  } 
  public void setX(T x) { 
  this.x = x; 
  } 
  } 
  public class GenericsFooDemo { 
  public static void main(String args[]){ 
  GenericsFoo<String> strFoo=new GenericsFoo<String>("Hello Generics!"); 
  GenericsFoo<Double> douFoo=new GenericsFoo<Double>(new Double("33")); 
  GenericsFoo<Object> objFoo=new GenericsFoo<Object>(new Object()); 
  System.out.println("strFoo.getX="+strFoo.getX()); 
  System.out.println("douFoo.getX="+douFoo.getX()); 
  System.out.println("objFoo.getX="+objFoo.getX()); 
  } 
  } 
  运行结果: 
  strFoo.getX=Hello Generics! 
  douFoo.getX=33.0 
  objFoo.getX=java.lang.Object@19821f 

  和使用“Object泛型”方式实现结果的完全一样,但是这个Demo简单多了,里面没有强制类型转换信息。
  下面解释一下上面泛型类的语法:
  使用<T>来声明一个类型持有者名称,然后就可以把T当作一个类型代表来声明成员、参数和返回值类型。
  当然T仅仅是个名字,这个名字可以自行定义。
  class GenericsFoo<T> 声明了一个泛型类,这个T没有任何限制,实际上相当于Object类型,实际上相当于 class GenericsFoo<T extends Object>。
  与Object泛型类相比,使用泛型所定义的类在声明和构造实例的时候,可以使用“<实际类型>”来一并指定泛型类型持有者的真实类型。类如
  GenericsFoo<Double> douFoo=new GenericsFoo<Double>(new Double("33"));
  当然,也可以在构造对象的时候不使用尖括号指定泛型类型的真实类型,但是你在使用该对象的时候,就需要强制转换了。比如:GenericsFoo douFoo=new GenericsFoo(new Double("33"));
  实际上,当构造对象时不指定类型信息的时候,默认会使用Object类型,这也是要强制转换的原因。
编辑本段泛型的高级应用
1、限制泛型的可用类型
  在上面的例子中,由于没有限制class GenericsFoo<T>类型持有者T的范围,实际上这里的限定类型相当于Object,这和“Object泛型”实质是一样的。限制比如我们要限制T为集合接口类型。只需要这么做:
  class GenericsFoo<T extends Collection>,这样类中的泛型T只能是Collection接口的实现类,传入非Collection接口编译会出错。
  注意:<T extends Collection>这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的extends已经不是继承的含义了,应该理解为T类型是实现Collection接口的类型,或者T是继承了XX类的类型。
  下面继续对上面的例子改进,我只要实现了集合接口的类型:
  public class CollectionGenFoo<T extends Collection> { 
  private T x; 
  public CollectionGenFoo(T x) { 
  this.x = x; 
  } 
  public T getX() { 
  return x; 
  } 
  public void setX(T x) { 
  this.x = x; 
  } 
  } 
  实例化的时候可以这么写: 
  public class CollectionGenFooDemo { 
  public static void main(String args[]) { 
  CollectionGenFoo<ArrayList> listFoo = null; 
  listFoo = new CollectionGenFoo<ArrayList>(new ArrayList()); 
  //出错了,不让这么干。 
  // CollectionGenFoo<Collection> listFoo = null; 
  // listFoo=new CollectionGenFoo<ArrayList>(new ArrayList()); 
  System.out.println("实例化成功!"); 
  } 
  } 

  当前看到的这个写法是可以编译通过,并运行成功。可是注释掉的两行加上就出错了,因 为<T extends Collection>这么定义类型的时候,就限定了构造此类实例的时候T是确定的一个类型,这个类型实现了Collection接口,但是实现 Collection接口的类很多很多,如果针对每一种都要写出具体的子类类型,那也太麻烦了,我干脆还不如用Object通用一下。别急,泛型针对这种 情况还有更好的解决方案,那就是“通配符泛型”。
2、通配符泛型
   为了解决类型被限制死了不能动态根据实例来确定的缺点,引入了“通配符泛型”,针对上面的例子,使用通配泛型格式为<? extends Collection>,“?”代表未知类型,这个类型是实现Collection接口。那么上面实现的方式可以写为:
  public class CollectionGenFooDemo { 
  public static void main(String args[]) { 
  CollectionGenFoo<ArrayList> listFoo = null; 
  listFoo = new CollectionGenFoo<ArrayList>(new ArrayList()); 
  //现在不会出错了 
  CollectionGenFoo<? extends Collection> listFoo1 = null; 
  listFoo=new CollectionGenFoo<ArrayList>(new ArrayList()); 
  System.out.println("实例化成功!"); 
  } 
  } 

  注意:
  1、如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类了。也就是任意类。
  2、通配符泛型不单可以向下限制,如<? extends Collection>,还可以向上限制,如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。
  3、泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。这些都泛型类中泛型的使用规则类似。
编辑本段泛型方法
  是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。如:
  public class ExampleA { 
  public <T> void f(T x) { 
  System.out.println(x.getClass().getName()); 
  } 
  public static void main(String[] args) { 
  ExampleA ea = new ExampleA(); 
  ea.f(" "); 
  ea.f(10); 
  ea.f('a'); 
  ea.f(ea); 
  } 
  } 
  输出结果: 
  java.lang.String 
  java.lang.Integer 
  java.lang.Character 
  ExampleA 

  使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。
  需要注意,一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。
分享到:
评论

相关推荐

    JDK1.5新特性泛型_深入研究.doc

    ### JDK1.5新特性泛型深入研究 #### 一、引言 随着软件工程的发展,类型安全成为了程序设计中的一个重要考量因素。Java作为一种广泛使用的编程语言,在其发展历程中不断引入新的特性以满足日益增长的需求。JDK1.5...

    java JDK1.5---32位和64位

    1. **泛型(Generics)**:这是JDK 1.5最重要的特性之一,允许在类、接口和方法中声明参数化类型,从而提高了代码的类型安全性和重用性。泛型有助于减少类型转换的错误,并在编译时期就能发现潜在的问题。 2. **...

    JDK1.5-1.6-1.7新特性

    在Java的JDK 1.5到1.7版本中,引入了一系列的新特性,极大地提升了开发效率和代码的可读性。以下是对这些新特性的详细介绍: 1. **自动装箱与拆箱**: 自动装箱允许基本类型与对应的包装类之间进行无缝转换。在JDK...

    jdk1.5-jar package

    总的来说,这个“jdk1.5-jar package”包含的是Java 5.0开发环境中的`jar`工具及其相关组件,它对于理解并使用Java 5.0的新特性、开发和打包Java应用程序至关重要。这个压缩包可能包含了JDK的安装程序、文档、示例...

    JDK1.5-1.6-1.7之新特性总结-1

    泛型是JDK 1.5最重要的特性之一,它允许在类、接口和方法中定义类型参数,从而增强了类型安全性和代码重用。例如,可以定义一个通用的集合类`List&lt;T&gt;`,其中T代表任意类型。泛型还可以用于限制方法的参数类型,避免...

    详细介绍JDK1.5的各种新特性

    1. **泛型(Generics)**:泛型是JDK1.5引入的最大变革之一。它允许在类、接口和方法中使用类型参数,提高了代码的类型安全性和重用性。泛型帮助程序员在编译时检查类型错误,避免了运行时的强制类型转换,使代码...

    jdk1.5的新特性泛型的实例代码

    Java开发工具包(JDK)1.5引入了一项重大改进,那就是泛型(Generics)。泛型是Java编程语言中的一个关键特性,它允许在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。通过泛型,...

    jdk1.5新特性,泛型,for:each

    泛型是JDK 1.5引入的一项革命性特性,它允许在类、接口和方法中声明类型参数,从而增强了代码的类型安全性。在使用泛型之前,集合框架中的元素只能被定义为Object类型,导致在添加和取出元素时需要进行强制类型转换...

    java经典教程-JDK1.5的泛型实现

    Java泛型是自JDK 1.5版本引入的一项重要特性,它极大地提高了代码的类型安全性和重用性。在本教程中,我们将深入探讨Java...通过阅读“JDK1.5的泛型实现.pdf”这份文档,你应该能更深入地理解泛型的细节和实际应用。

    JDK1.5新特性

    2. **泛型**:泛型是1.5最重要的新特性之一,它允许在类、接口和方法中使用类型参数,增强了类型安全性和代码重用性。泛型可以限制集合元素的类型,避免了类型转换错误。 3. **枚举类(enum)**:之前的Java中,...

    jdk1.5_forLinux.zip

    总的来说,JDK 1.5 for Linux不仅为开发者提供了强大的编程工具,还通过引入一系列新特性,推动了Java语言的发展,使之更加高效和易用。无论是初学者还是经验丰富的开发者,都应熟悉并掌握这一版本,因为它对于理解...

    jdk1.5x64位 windows版.zip

    其次,泛型(Generics)是JDK1.5的一大亮点。泛型允许在定义类、接口和方法时指定参数类型,增强了类型检查,减少了类型转换的麻烦,同时也减少了运行时的类型错误。泛型还引入了通配符,如"? extends T"和"? super ...

    linux系统jdk1.5下载

    JDK1.5引入了一些重要的特性,如增强的for循环(foreach)、匿名内部类的改进、枚举类型以及泛型的初步支持。这些特性对Java编程产生了深远影响,提升了代码的可读性和安全性。 然而,由于JDK1.5已不再受官方支持,...

    jdk1.5 windows版本 64位

    它于2004年9月30日正式发布,引入了许多新的特性,如自动内存管理的增强(例如泛型、枚举、变量类型推断、增强的for循环),对XML支持的加强,新的日期/时间API,以及改进的反射机制。这些特性显著提升了Java编程的...

    Java-jdk1.5安装包

    JDK1.5,也称为Java 5.0,是一个重要的版本,它引入了许多新的特性和改进,对Java语言的发展产生了深远影响。 一、泛型(Generics) 在Java 5.0中,最重要的特性之一就是泛型的引入。泛型允许开发者在定义类、接口...

    jdk1.5新特性

    ### JDK 1.5 新特性详解 #### 泛型编程 **定义与作用:** 泛型编程是 Java 1.5 引入的一项重要特性,它允许开发者在编译时进行类型安全检查,从而避免了运行时可能出现的类型转换异常。通过在编译阶段检查类型安全...

    jdk1.5新特性关于动态参数,泛型等

    泛型是 JDK 1.5 最重要的改进之一,它允许在定义集合类时指定元素类型,从而在编译时就能进行类型检查。这样可以防止运行时的 ClassCastException,增加代码的类型安全性。例如,使用泛型,我们可以创建一个只存储 ...

    jdk1.5后的特性.rar

    枚举是 JDK 1.5 中引入的另一种新特性,用于替代传统的常量类,提供了一种更安全、更强大的方式来定义固定数量的值。枚举类型可以包含方法、变量,甚至实现接口。 - **声明枚举**:使用 `enum` 关键字定义枚举,如 ...

    jdk1.5(jdk-1_5_0_08-windows-i586-p.exe)

    泛型是JDK 1.5引入的最重要的特性之一,允许开发者在类、接口和方法中使用类型参数,提高了代码的类型安全性和可读性,减少了强制类型转换的需要。 2. **枚举(Enums)** JDK 1.5引入了枚举类型,使得定义常量...

    JDK1.5,JDK1.5

    泛型是JDK1.5最重要的特性之一,它允许在类、接口和方法声明中使用类型参数,以实现数据类型的参数化。泛型提高了代码的类型安全性和可读性,减少了类型转换的需要,并允许编译器检查类型错误。 2. **自动装箱与...

Global site tag (gtag.js) - Google Analytics