首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

java泛型示范

2012-10-15 
java泛型示例使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有

java泛型示例
使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。
泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。
一个泛型类就是具有一个或多个类型变量的类。
如下面的Pair例子,就是一个泛型类

package ch13genic;public class Pair<T> {private T first;private T second;public Pair(){first = null;second = null;}public T getFirst() {return first;}public void setFirst(T first) {this.first = first;}public T getSecond() {return second;}public void setSecond(T second) {this.second = second;}public Pair(T first, T second) {this.first = first;this.second = second;}}



该类引人了类型变量T,用尖括号<>扩起,放在类名的后面,泛型类可以有多个类型变量,例如public class Pair<T,U>{....},
用具体的类型替换类型变量就可以实例化泛型类型:如Pair<String>,泛型类可以看做普通类的工厂。
package ch13genic;public class PairTest1{   public static void main(String[] args)   {      String[] words = { "Mary", "had", "a", "little", "lamb" };      Pair<String> mm = ArrayAlg.minmax(words);      System.out.println("min = " + mm.getFirst());      System.out.println("max = " + mm.getSecond());                 String midStr = ArrayAlg.<String>getMiddle(words); //调用泛型方法,也可以省略<String>,因为编译器根据words匹配T[] a,判断出T一定是String。     System.out.println(midStr);     //     int[] a = {1,23,45,56,3};//     int aMid = ArrayAlg.getMiddle(a);            编译出错,为什么?猜测:因为T是一个类型变量,代表的是一个类,而int只是基本类型     //     Integer[] a ={1,23,45,56,3};//     int aMid = ArrayAlg.getMiddle(a);//     System.out.println(aMid);   }}class ArrayAlg{   public static Pair<String> minmax(String[] a)    {      if (a == null || a.length == 0) return null;      String min = a[0];      String max = a[0];      for (int i = 1; i < a.length; i++)      {         if (min.compareTo(a[i]) > 0) min = a[i];         if (max.compareTo(a[i]) < 0) max = a[i];      }      return new Pair<String>(min, max);   }      public static <T> T getMiddle(T[] a){      //示意:带有类型参数的方法。由于这个类不是在泛型类中定义的,要用<T>引人类型变量,它放在修饰符和返回值之间   return a[a.length/2];   }   }

类型变量的限定
有时类或方法需要对类型变量加以约束。下面是一个典型的例子
class ArrayAlg{public static <T> T min(T[] a) {if (a == null || a.length == 0)return null;T min = a[0];for (int i = 0; i < a.length; i++) {if (min.compareTo(a[i]) < 0)min = a[i];}return min;}}
这里有一个问题,变量min的类型为T,意味着它可以是任何一个类的对象。怎么才能确信T所属的类有compareTo方法呢?
解决这个问题的答案是将T限制为实现了Comparable接口的类,如
public static <T extends Comparable> T min(T[] a){}
实际上,Comparable本身就是一个泛型接口:public interface Comparable<T>,唯一的方法:compareTo(T o) 如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
可能有些奇怪,为什么使用关键字extends而不是implements?比较,Comparable是一个接口啊,下面的符号:
<T extends BoundingType>
表示T应该是绑定类型的子类型,T和绑定类型可以是类,也可以是接口。
一个类型变量可以有多个限定,例如
T extends Comparable & Serializable
限定类型用 & 分隔,这是因为用逗号分隔类型变量
package ch13genic;import java.util.*;public class PairTest2{   public static void main(String[] args)   {      GregorianCalendar[] birthdays =          {             new GregorianCalendar(1906, Calendar.DECEMBER, 9), // G. Hopper            new GregorianCalendar(1815, Calendar.DECEMBER, 10), // A. Lovelace            new GregorianCalendar(1903, Calendar.DECEMBER, 3), // J. von Neumann            new GregorianCalendar(1910, Calendar.JUNE, 22), // K. Zuse         };      Pair<GregorianCalendar> mm = ArrayAlg.minmax(birthdays);      System.out.println("min = " + mm.getFirst().getTime());      System.out.println("max = " + mm.getSecond().getTime());   }}class ArrayAlg{   /**      Gets the minimum and maximum of an array of objects of type T.      @param a an array of objects of type T      @return a pair with the min and max value, or null if a is       null or empty   */   public static <T extends Comparable> Pair<T> minmax(T[] a)    {      if (a == null || a.length == 0) return null;      T min = a[0];      T max = a[0];      for (int i = 1; i < a.length; i++)      {         if (min.compareTo(a[i]) > 0) min = a[i];         if (max.compareTo(a[i]) < 0) max = a[i];      }      return new Pair<T>(min, max);   }}

泛型的约束和限制
不能用类型参数替换基本类型,因此没有Pair<double>,只有Pair<Double>.虚拟机没有泛型类型对象,所有对象都是
普通对象。所有的类型查询只产生原始类型,如List而非List<String>等。getClass总是返回原始类型。
if(a instanceof Pair<String>)等价if(a instanceof Pair)
Pair<String> p = new Pair("first", "second");Pair<Integer> p1 = new Pair();System.out.println(p.getClass().getName());// ch13genic.PairSystem.out.println(p1.getClass().getName()); // ch13genic.PairList<String> l1 = new ArrayList<String>();List<Integer> l2 = new ArrayList<Integer>();System.out.println(l1.getClass().getName());// java.util.ArrayListSystem.out.println(l2.getClass().getName()); // java.util.ArrayList
泛型类不能扩展Throwable。如public class Problem<T> extends Exception {
。。。
} //error The generic class Problem<T> may not subclass java.lang.Throwable
不能在catch子句中使用类型变量。如下面的方法将不能编译:
try{//do work}catch(T e){  //error:Cannot use the type parameter T in a catch block//logger.info("");}}

但是,在异常声明中可以使用类型变量。下面这个方法是合法的:
public static <T extends Throwable> void doWork(T t) throws T{//oktry{//do work}catch(Throwable e){  //error:Cannot use the type parameter T in a catch block t.initCause(e);throw t;}}
不能申明参数化类型的数组,如:
Pair<String>[] table = new Pair<String>(10); //error
如果需要收集参数化类型对象,直接使用ArrayList:ArrayList<Pair<String>>最安全且有效。
不能实例化泛型类型,如:
public Pair(T first, T second) { //errorthis.first = new T();this.second = new T();}

不能建立一个泛型数组,如:
T[] t = new T[20]; //error
不能在静态域或方法中引用类型变量,如:

public class Singleton<T>  {private static T singleInstance; //error:Cannot make a static reference to the non-static type Tpublic static T getSingleInstance(){//errorif(singleInstance==null){//construct new instance of T}return singleInstance;}}

一个类和一个子类,Pair<Employee>与Pair<Manager>,前者是后者的子类吗?不是。无论S、T有何关系,Pair<S>和Pair<T>没有什么联系。

热点排行