`

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.Pair
		System.out.println(p1.getClass().getName()); // ch13genic.Pair

		List<String> l1 = new ArrayList<String>();
		List<Integer> l2 = new ArrayList<Integer>();
		System.out.println(l1.getClass().getName());// java.util.ArrayList
		System.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{//ok
		try{
			//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) { //error
		this.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 T

	public static T getSingleInstance(){//error
		if(singleInstance==null){
//			construct new instance of T
		}
		return singleInstance;
	}
	
}

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

相关推荐

Global site tag (gtag.js) - Google Analytics