【笔记29】优先考虑泛型

// Initial attempt to generify Stack = won't compile!
public class Stack<E> {
	private E[] elements;
	private int size = 0;
	private static final int DEFAULT_INITIAL_CAPACITY = 16;
	
	public Stack() {
		elements = new E[DEFAULT_INITIAL_CAPACITY];
	}
 
	public void push(E e) {
		ensureCapacity();
		elements[size++] = e;
	}
 
	public E pop() {
		if (size == 0)
			throw new EmptyStackException();
		E result = elements[--size];
		elements[size] = null;
		return result;
	}
	
	public boolean isEmpty() {
		return size == 0;
	}
	
	private void ensureCapacity() {
		if (elements.length == size)
			elements = Arrays.copyOf(elements, 2 * size + 1);
	}
}

上面这个泛型栈的例子会存在一个错误,25条说过,E是不可具化的,而数组是可具化的,所以不能用E来使用诸如new E[]这样的数组申请方法,为了解决这个问题,有如下两种方法:

1、绕开创建泛型数组的禁令,直接创建一个Object的数组,并将它转换成泛型数组类型。

public Stack() {
     elements = (E[]) new Object[DEFAULT_INITAL_CAPACITY];
}

至此,又得到了一条警告信息,因为我们要把Object型的数组赋给E型,因为编译器无法确定E的具体类型,所以警告这是不是类型安全的。但是由于elements只有在push中使用,且压进的是E型元素,所以我们可以判断出这是安全的,因此加上强制类型转换(E())new Object[...],这是解决上面错误问题的第一种方法。但是必须确保未受检的转换不会危及到程序的类型安全,相关的数组保存在一个私有域中,永远不会被返回到客户端去,或者传递给任何方法,也就是说存在不稳定的因素,但是是完成在服务端可控的。一旦证明了未受检转换是安全的,就要在尽可能小的范围内禁止警告,在这种情况下,构造器只包含未受检的数组创建,因此可以在整个构造器中禁止这条警告。

2、将elements域的类型从E[]改为Object[]。

private Object[] elements;

E result = (E) elements[--size];

与第一种情况类似。这也会得到一条警告,同样的,也可证明这种情况下是安全的,因此可以禁止该警告,我们只要在包含未受检转换的任务上禁止警告,而不是在整个pop方法上就可以了。如下

public E pop() {        
    if (size == 0)            
        throw new EmptyStackException();        
    @SuppressWarnings("unchecked")        
    E result = (E)elements[--size];        
    elements[size] = null;        
    return result;    
}

       这两种方法,一般来说禁止数组类型的未受检转换比禁止标题类型更危险,所以建议使用第二种方法。但是在比这个例子更实际的泛型中,或许代码中会有多个地方需要从数组中读取元素,因此第一种方法比第二种方法开销更小一些,这也是第一种方法更常用的原因。这个例子看起来违反了25条(它告诉我们对于泛型列表要优于数组),实际上因为JAVA并不是生来就支持列表,所以有些泛型如ArrayList必须使用数组来实现,有的时候为了提升性能,也会考虑用数组来实现,比如HashMap。

        有一些泛型限制了可允许的类型参数值。例如:考虑java.util.concurrent.DelayQueue,其声明如下:

class DelayQueue<E extends Delayed> implements BlockingQueue<E>;  

        类型参数列表要求实际的类型参数E必须是java,util.concurrent.Delayed的一个子类型,它允许DelayQueue实现及其客户端在DelayQueue元素上利用Delayed方法,无需显示的转换,注意,第一个类型都是自身的子类型,因此创建DelayQueue<Delayed>是合法的。

       总之,使用泛型比使用需要在客户端代码中进行转化的类型来的更安全。也更容易,在设计新类的时候,要确保它们不需要这种转换就可以使用。这通常意味着要把类做成是泛型的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值