第二十九条:首选泛型类型

一般来说,在自己的声明中进行参数化,以及使用JDK提供的泛型类型和方法,都不是特别困难。难得是自己写的泛型类型,但这是值得花时间学习的。

案例(来自第七条):

public class Stack {
// 基于Object的集合---选择对这个类进行泛型化
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

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

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public E pop() {
        if (size == 0)
            throw new EmptyStackException();
        E result = elements[--size];
        elements[size] = null; // Eliminate obsolete reference
        return result;
    }
    ... // no changes in isEmpty or ensureCapacity
}

 下一步就是将所有使用到Object类型的地方都替换为相应的类型参数,然后尝试编译到的程序:

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; // Eliminate obsolete reference
        return result;
    }
    ... // no changes in isEmpty or ensureCapacity
}

这时出现了编译错误,elements = new E[DEFAULT_INITIAL_CAPACITY];因为我们不可具体化的类型(如E)数组。有两种方法来解决:

第一种规避了对泛型数组创建的禁用:创建一个 Object 数组并将其转换为泛型数组类型
可以加上声明:

@SuppressWarnings("unchecked")
public Stack() {
    elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}

第二种是将属性元素的类型从 E[] 更改为 Object[],当然会有一个错误;
可以通过将从数组中检索到的元素转换为 E 来将此错误更改为警告:

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

可以加上声明:

public E pop() {
    if (size == 0)
        throw new EmptyStackException();

    // push requires elements to be of type E, so cast is correct
    @SuppressWarnings("unchecked") E result =
        (E) elements[--size];

    elements[size] = null; // Eliminate obsolete reference
    return result;
}

第一个更可读:数组被声明为 E[] 类型,清楚地表明它只包含 E 实例。 它也更简洁:在一个典型的泛型类中,你从代码中的许多点读取数组; 第一种技术只需要一次转换(创建数组的地方);
而第二种技术每次读取数组元素都需要单独转换。 因此,第一种技术是优选的并且在实践中更常用。 但是,它确实会造成堆污染(heap pollution)( 32 ):数组的运行时类型与编译时类型不匹配(除非 E 碰巧是 Object)。 这使得一些程序员非常不安,他们选择了第二种技术,尽管在这种情况下堆的污染是无害的。

总而言之,与需要在客户端代码中进行强制类型转换的类型相比,泛型类型更安全,而且更容易使用。当设计新的类型时,应该确保他们可以在不进行此类转换的情况下使用。这用通常意味着要将其设计为泛型类型。如果有任何一个现有的类型本应该是泛型类型,但实际上却不是,那就将其泛型化。这将使这些类型的新用户使用起来更容易,同时不会破坏已有的客户端

 所有文章无条件开放,顺手点个赞不为过吧!

                                             

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值