`
xuehongliang
  • 浏览: 93946 次
  • 性别: Icon_minigender_1
  • 来自: 辽宁
社区版块
存档分类
最新评论

JDK5.0新特性的学习--泛型(下)

    博客分类:
  • java
阅读更多
没有参数的情况下使用泛型

    既然在J2SE 5.0中收集类型已经泛型化,那么,原来的使用这些类型的代码将如何呢?很幸运,他们在JAVA 5中将继续工作,因为你能使用没有参数的泛型。比如,你能继续像原来一样使用List接口,正如下面的例子一样。

List stringList1 = new ArrayList();
stringList1.add("Java 1.0 - 5.0");
stringList1.add("without generics");
String s1 = (String) stringList1.get(0);
一个没有任何参数的泛型被称为原型(raw type)。它意味着这些为JDK1.4或更早的版本而写的代码将继续在java 5中工作。

尽管如此,一个需要注意的事情是,JDK5编译器希望你使用带参数的泛型。否则,编译器将提示警告,因为他认为你可能忘了定义类型变量s。比如,编译上面的代码的时候你会看到下面这些警告,因为第一个List被认为是原型。

Note: com/brainysoftware/jdk5/app16/GenericListTest.java
        uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

当你使用原型时,如果你不想看到这些警告,你有几个选择来达到目的:
1.编译时带上参数-source 1.4
2.使用@SupressWarnings("unchecked")注释
3.更新你的代码,使用List. List的实例能接受任何类型的对象,就像是一个原型List。然而,编译器不会报错。

使用 ? 通配符
   前面提过,如果你声明了一个List<atype></atype>, 那么这个List对aType起作用,所以你能储存下面这些类型的对象:
1.一个aType的实例
2.它的子类的实例(如果aType是个类)
3.实现aType接口的类实例(如果aType是个接口)
但是,请注意,一个泛型本身是个JAVA类型,就像java.lang.String或java.io.File一样。传递不同的类型变量给泛型可以创建不同的JAVA类型。比如,下面例子中list1和list2引用了不同的类型对象。

List
list1 = new ArrayList();
List<string></string> list2 = new ArrayList<string></string>();
 
list1指向了一个类型变量s为java.lang.Objects 的List而list2指向了一个类型变量s为String 的List。所以传递一个List<string></string>给一个参数为List的函数将导致compile time错误。下面列表可以说明:

public class AllowedTypeTest {
  public static void doIt(Listl) {
  }
  public static void main(String[] args) {
    List<string></string> myList = new ArrayList<string></string>();
    // 这里将产生一个错误
    doIt(myList);
  }
}
上面的代码无法编译,因为你试图传递一个错误的类型给函数doIt。doIt的参数是List二你传递的参数是List<string></string>。
可以使用 ? 通配符解决这个难题。List 意味着一个对任何对象起作用的List。所以,doIt可以改为:

public static void doIt(List l) {}

    在某些情况下你会考虑使用 ? 通配符。比如,你有一个printList函数,这个函数打印一个List的所有成员,你想让这个函数对任何类型的List起作用时。否则,你只能累死累活的写很多printList的重载函数。下面的列表引用了使用 ? 通配符的printList函数。

public class WildCardTest {

  public static void printList(List list) {
    for (Object element : list) {
      System.out.println(element);
    }
  }
  public static void main(String[] args) {
    List<string></string> list1 = new ArrayList<string></string>();
    list1.add("Hello");
    list1.add("World");
    printList(list1);

    List<integer></integer> list2 = new ArrayList<integer></integer>();
    list2.add(100);
    list2.add(200);
    printList(list2);
  }
}

这些代码说明了在printList函数中,List表示各种类型的List对象。然而,请注意,在声明的时候使用 ? 通配符是不合法的,像这样:

List myList = new ArrayList(); // 不合法

如果你想创建一个接收任何类型对象的List,你可以使用Object作为类型变量,就像这样:

List
myList = new ArrayList();
 
在函数中使用界限通配符
在之前的章节中,你学会了通过传递不同的类型变量s来创建不同JAVA类型的泛型,但并不考虑类型变量s之间的继承关系。在很多情况下,你想一个函数有不同的List参数。比如,你有一个函数getAverage,他返回了一个List中成员的平均值。然而,如果你把List<number></number>作为getAverage的参数,你就没法传递List<integer></integer> 或List<double></double>参数,因为List<number></number>和List<integer></integer> 和List<double></double>不是同样的类型。

你能使用原型或使用通配符,但这样无法在编译时进行安全类型检查,因为你能传递任何类型的List,比如List<string></string>的实例。你可以使用List<number></number>作为参数,但是你就只能传递List<number></number>给函数。但这样就使你的函数功能减少,因为你可能更多的时候要操作List<integer></integer>或List<long></long>,而不是List<number></number>。

J2SE5.0增加了一个规则来解决了这种约束,这个规则就是允许你定义一个上界(upper bound) 类型变量.在这种方式中,你能传递一个类型或它的子类。在上面getAverage函数的例子中,你能传递一个List<number></number>或它的子类的实例,比如List<integer></integer> or List<float></float>。

使用上界规则的语法这么定义的:GenericType. 比如,对getAverage函数的参数,你可以这么写List. 下面例子说明了如何使用这种规则。
public class BoundedWildcardTest {
  public static double getAverage(List<!----> numberList)
  {
    double total = 0.0;
    for (Number number : numberList)
      total += number.doubleValue();
    return total/numberList.size();
  }

  public static void main(String[] args) {
    List<integer></integer> integerList = new ArrayList<integer></integer>();
    integerList.add(3);
    integerList.add(30);
    integerList.add(300);
    System.out.println(getAverage(integerList)); // 111.0
    List<double></double> doubleList = new ArrayList<double></double>();
    doubleList.add(3.0);
    doubleList.add(33.0);
    System.out.println(getAverage(doubleList)); // 18.0
  }
}
由于有了上界规则,上面例子中的getAverage函数允许你传递一个List<number></number> 或一个类型变量是任何java.lang.Number子类的List。

下界规则
关键字extends定义了一个类型变量的上界。通过使用super关键字,我们可以定义一个类型变量的下界,尽管使用的情况不多。比如,如果一个函数的参数是List,那么意味着你可以传递一个List<integer></integer>的实例或者任何java.lang.Integer的超类(superclass)。

创建泛型

前面的章节主要说明了如何使使用泛型,特别是集合框架中的类。现在我们开始学习如何写自己的泛型。

基本上,除了声明一些你想要使用的类型变量s外,一个泛型和别的类没有什么区别。这些类型变量s位于类型后面的<>中。比如,下面的Point就是个泛型。一个Point对象代表了一个系统中的点,它有横坐标和纵坐标。通过使Point泛型化,你能定义一个点实例的精确程度。比如,如果一个Point对象需要非常精确,你就把Double作为类型变量。否则,Integer 就够了。
package com.brainysoftware.jdk5.app16;
public class Point<t></t> {
  T x;
  T y;
  public Point(T x, T y) {
    this.x = x;
    this.y = y;
  }
  public T getX() {
    return x;
  }
  public T getY() {
    return y;
  }
  public void setX(T x) {
    this.x = x;
  }
  public void setY(T y) {
    this.y = y;
  }
}
在这个例子中,T是Point的类型变量 。T是getX和getY的返回值类型,也是setX和setY的参数类型。此外,构造函数结合两个T参数。
使用point类就像使用别的类一样。比如,下面的例子创建了两个Point对象:ponint1和point2。前者把Integer作为类型变量,而后者把Double作为类型变量。

Point<integer></integer> point1 = new Point<integer></integer>(4, 2);
point1.setX(7);
Point<double></double> point2 = new Point<double></double>(1.3, 2.6);
point2.setX(109.91);
总结
泛型使代码在编译时有了更严格的类型检查。特别是在集合框架中,泛型有两个作用。第一,他们增加了对集合类型在编译时的类型检查,所以集合类所能持有的类型对传递给它的参数类型起了限制作用。比如你创建了一个持有strings的java.util.List实例,那么他就将不能接受Integers或别的类型。其次,当你从一个集合中取得一个元素时,泛型消除了类型转换的必要。
泛型能够在没有类型变量的情况下使用,比如,作为原型。这些措施让Java 5之前的代码能够运行在JRE 5中。但是,对新的应用程序,你最好不要使用原型,因为以后Java可能不支持他们。

你已经知道通过传递不同类型的类型变量给泛型可以产生不同的JAVA类型。就是说List<string></string>和List的类型是不同的。尽管String是java.lang.Object。但是传递一个List<string></string>给一个参数是List的函数会参数会产生编译错误(compile error)。函数能用 ? 通配符使其接受任何类型的参数。List 意味着任何类型的对象。
最后,你已经看到了写一个泛型和别的一般JAVA类没有什么区别。你只需要在类型名称后面的<>中声明一系列的类型变量s就行了。这些类型变量s就是返回值类型或者参数类型。根据惯例,一个类型变量用一个大写字母表示。
分享到:
评论
1 楼 ueseu 2007-04-24  
原文在哪?

相关推荐

    jdk5.0新特性ppt

    jdk5.0新特性 包括泛型,增强的for循环,自动的封箱和拆箱

    jdk-6u39-windows-x64-demos.zip

    JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛...从SUN的JDK5.0开始,提供了泛型等非常实用的功能,其版本也不断更新,运行效率得到了非常大的提高。

    JDK 5.0中的泛型类型学习

    JDK 5.0 中增加的泛型类型,是 Java 语言中类型安全的一次重要改进。但是,对于初次使用泛型类型的用户来说,泛型的某些方面看起来可能不容易明白,甚至非常奇怪。在本月的“Java 理论和实践”中,Brian Goetz 分析...

    jdk5.0新特性汇总(超级详细)

    加强for循环,静态导入,枚举,泛型,反射,注解,类加载器,代理等。张孝祥总结,绝对经典。

    Java5.0泛型编程

    本文重点讲解JDK5.0支持的新功能-----Java的泛型, 使你快速掌握。

    jdk-8u241-windows-x64

    JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛...从SUN的JDK5.0开始,提供了泛型等非常实用的功能,其版本也不断更新,运行效率得到了非常大的提高。

    JDK5.0新特性 自动包装和解包等新功能

    自动包装和解包 更优化的循环语句 参数可变的方法 printf 枚举 静态引用 泛型

    java中的泛型-详细

    本文将讲解JDK5.0支持的新功能-----Java的泛型.  1、Java泛型  其实Java的泛型就是创建一个用类型作为参数的类。就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1、str2的...

    jdk1.6 64位 官方正式版 jdk-6u45-windows-x64

    下载后解压运行。JDK Java Development Kit是SunMicrosystems针对Java开发员的产品。...从SUN的JDK5.0开始提供了泛型等非常实用的功能,其版本也不断更新,此次提供的jdk1.6运行效率得到了非常大的提高。

    JDK5一些新特性关于枚举泛型等

    JDK5.0的新特性一、枚举类型generic-泛型自动解包装与自动包装的功能

    Jdk5.0泛型

    Jdk5.0泛型原理及使用

    Java JDK 5.0学习笔记(第二部分)

    本书是作者良葛格本人近几年来学习Java的心得笔记,结构按照作者的学习脉络依次展开,从什么是Java、如何配置Java开发环境、基本的Java语法到程序流程控制、管理类文件、异常处理、枚举类型、泛型、J2SE中标准的API...

    JDK 5.0中的泛型类型学习.pdf

    JDK 5.0中的泛型类型学习.docx

    良葛格Java JDK 5.0学习笔记

    本书是作者良葛格本人近几年来学习Java的心得笔记,结构按照作者的学习脉络依次展开,从什么是Java、如何配置Java开发环境、基本的Java语法到程序流程控制、管理类文件、异常处理、枚举类型、泛型、J2SE中标准的API...

    Jdk5.0泛型指南(转贴)

    博文链接:https://lkfnn.iteye.com/blog/33406

    详细描述jdk1.5新特性

    jdk1.5新特性 泛类型和泛型方法是Java5.0 中的新特性。一种泛类型用一个或多个泛型变量定义,可以有一个或多个,泛型变量做参数占位符或做返回值 的方法。

Global site tag (gtag.js) - Google Analytics