美文网首页
[Effective Java] Item 26: Favor

[Effective Java] Item 26: Favor

作者: YoungJadeStone | 来源:发表于2019-04-18 08:27 被阅读0次

Item 26告诉我们要优先考虑泛型。

原因

比如下面的例子里,在参数化collection的时候:

// object-based collection - a prime candidate for fenerics
public class Stack {
  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++];
  }
  public Object pop() {
    if (size == 0) {
      throw new EmptyStackException();
    }
    Object result = elements[--size];
    elements[size] = null; // eliminate obsolete reference
    return result;
  }
  public boolean isEmpty() {
    return size == 0;
  }
  private void ensureCapacity() {
    if (elements.length == size) {
      elements = Arrays.copyOf(elements, 2 * size + 1);
    }
  }
}

在上面的例子中,我们用的是Object,所以在具体使用Stack里面的元素的时候,我们需要进行类型转换(cast)。而这些类型转换在run-time是很容易失败的。比起run-time的failure,我们更希望在compiler的时候就抓住。

问题

现在我们把上面的Object都用泛型来表示:

// 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++];
  }
  public E pop() {
    if (size == 0) {
      throw new EmptyStackException();
    }
    E result = elements[--size];
    elements[size] = null; // eliminate obsolete reference
    return result;
  }
  ... // no change in isEmpty or ensureCapacity
}

结果我们会遇到下面的error/warning:

Stack.java:8: generic array creation
            elements = new E[DEFAULT_INITIAL_CAPACITY];

这是因为根据Item 25里面所说,我们不能创建一个泛型数组。

解决方法

我们有两个解决方法:

  1. 避开这个限制。我们创建Object array,然后再cast成泛型。
  2. 把stack里的field E[] elements变成Object[] elements。

第一个方法中,当我们创建Object array,然后再cast成泛型时,compiler会给我们一个warning:

Stack.java:8: warning: [unchecked] unchecked cast
found   : Object[], required: E[]
            elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];

这个warning的目的是为了typesafe。因为我们知道Stack里面所有加进去的元素都是泛型E,这个cast是typesafe的,所以我们可以抑制这个warning。

// the elements array will contain only E instances from push(E).
// this is sufficient to ensure type safety, but the runtime
// type of the array won't be E[]; it will always be Object[]!
@SuppressWarnings("unchecked")
public Stack() {
  elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}

第二个方法中,我们把stack里的field E[] elements变成Object[] elements。这样会有下面的error:

Stack.java:19: incompatible types
found   : Object, required: E
            E result = elements[--size];

如果我们对应的把Object cast成E,error没有了,但会有下面的warning:

Stack.java:19: warning: [unchecked] unchecked cast
found   : Object, required: E
            E result = (E) elements[--size];

同理,因为我们知道Stack里面所有加进去的元素都是泛型E,这个cast是typesafe的,所以我们可以抑制这个warning。

// appropriate suppression of unchecked warning
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;
}

这两种方法都可以使用。


Reference

相关文章

网友评论

      本文标题:[Effective Java] Item 26: Favor

      本文链接:https://www.haomeiwen.com/subject/vrkuwqtx.html