第12章 泛型程序设计

1.为什么要使用泛型

泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。
在Java增加泛型类之前,泛型程序设计使用继承实现的。

2.定义简单泛型类

public class Pair<T>{
        private T first;
        private T second;

        public Pair(){ first=null;second=null;}
        public Pair(T first,T second){ this.first=first;this.second=second;}

        public T getFirst(){ return first;}
        public T getSecond(){ return second;}

        public void setFirst(T first){ this.first=first;}
        public void setSecond(T second){ this.second=second;}
}

3.泛型方法

class ArrayAlg{
        public static <T> T getMiddle(T... a){
                return a[a.length/2];
        }
}

4.类型变量的限定

有时,类或方法需要对类型变量加以约束。例:
class ArrayAlg{
	public static <T> T min(T[] a){
		if(a==null||a.length==0) 
			return null;
		T smallest=a[0];
		for (int i=1;i<a.length;i++) {
			if (smallest.compareTo(a[i])>0) 
				smallest=a[i];
		}
		return smallest;
	}
}
变量smallest类型为T,怎么才能确信T所属的类有compareT方法呢?解决这个问题的方案是将T限制为实现了Comparable接口的类
public static <T extends Comparable> T min(T[] a)...

<T extends BoundingType>表示T应该是绑定类型的子类型。T和绑定类可以是类,也可以是接口。

多个限定:T extends Comparable & Serializable

5.泛型代码和虚拟机

虚拟机中没有泛型类型对象,所有对象都属于普通类。无论何时定义了一个泛型类型,都自动提供了一个相应的原始类型,原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量用Object)。Pair<T>的原始类型:
public class Pair{
	private Object first;
	private Object second;

	public Pair(Object first,Object second){
		this.first=first;
		this.second=second;
	}

	public Object getFirst(){ return first; }
	public Object getSecond(){ return second; }

	public void setFirst(Object first){ this.first=first; }
	public void setSecond(Object second){ this.second=second; }
}
原始类型用第一个限定的类型变量来替换。
public class Interval<T extends Comparable & Serializable> implements Serializable{
	private T lower;
	private T upper;
	...
	public Interval(T first,T second){
		if (first.compareTo(second)<=0) {
			lower=first;
			upper=second;
		}
		else{
			lower=second;
			upper=first;
	}
}
原始类型:
public class Interval implements Serializable{
	private Comparable lower;
	private Comparable upper;
	...
	public Interval(Comparable first,Comparable second){ ... }
}
如果切换限定,原始类型用Serializable替换T,编译器必须要向Comparable插入强制类型转换。为了提高效率,应该将标签接口(没有方法的接口)放在边界列表的末尾。

5.1 翻译泛型表达式

(1)调用原始方法
(2)将返回的Object对象进行强制类型转换

5.2 翻译泛型方法

//泛型方法
public static <T extends Comparable> T min(T[] a)
//擦除类型后的方法
public static Comparable min(Comparable[] a)
示例:
class DateInterval extends Pair<Date>{
	public void setSecond(Date second){
		if(second.compareTo(getFirst())>=0)
			super.setSecond(second);
	}
	...
}
这个类擦除后变成
class DateInterval extends Pair{  //after erasure
	public void setSecond(Date second){ ... }
	...
}
存在另一个从Pair继承的setSecond方法,它有一个不同类型的参数Object
public void setSecond(Object second)
考虑下面的程序:
DateInterval interval=new DateInterval(...);
Pair<Date> pair=interval;//OK--assignment to superclass
pair.setSecond(aDate);
这里希望对setSecond的调用具有多态性,并调用最合适的那个方法。由于pair引用DateInterval对象,就应该调用DateInterval.setSecond。问题在于类型擦除与多态发生了冲突。为解决这个问题,编译器在DateInterval类中生成了一个桥方法。
public void setSecond(Object second){ setSecond((Date) second); }

Java泛型转换的事实:
·虚拟机中没有泛型,只有普通的类和方法
·所有的类型参数都用它们的限定类型替换
·桥方法被合成来保持多态
·为保持类型安全性,必要时插入强制类型转换

6.约束与局限性

(1)不能用基本类型实例化类型参数
(2)运行时类型检查只适用于原始类型 instanceof getClass方法 强制类型转换得到的都是原始类型
(3)不能创建参数化类型的数组 可以使用ArrayList
(4)Varargs警告
(5)不能实例化类型变量 不能使用new T(...),new T[...]或T.class这样的表达式
(6)泛型类的静态上下文中的类型变量无效 不能在静态域或方法中引用类型变量
(7)不能抛出或捕获泛型类的实例
(8)注意擦除后的冲突

7.泛型类型的继承规则

Pair<Manager>不是Pair<Employee>的一个子类

8.通配符类型

public static void printBuddies(Pair<Employee> p){
	Employee first=p.getFirst();
	Employee second=p.getSecond();
	System.out.println(first.getName()+" and "+second.getName()+" are buddies.");
}
不能将Pair<Manager>传递给这个方法,解决方法:使用通配符类型。
public static void printBuddies(Pair<? extends Employee> p)
Pair<? extends Employee>的方法:
? extends Employee getFirst()
void setFirst(? extends Employee)
这样将不能调用setFirst方法,编译器只知道需要某个Employee的子类型,但不知道是什么类型。它拒绝传递任何特定的类型,毕竟?不能用来匹配。

8.1 通配符的超类型限定

? super Manager
这个通配符限制为Manager的所有超类型。带有超类型限定的通配符可以为方法提供参数,但不能使用返回值。例:
? super Manager getFirst()
void setFirst(? super Manager)
编译器不知道setFirst的确切类型,但是可以使用任意Manager对象(或子类型)调用它,不能用Employee。如果调用getFirst,返回的对象类型不会得到保证,只能赋给Object。

9.反射和泛型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值