2010-10-24 51 views
7

现在,我有:的Java:如何实现`toArray`为`Collection`

public <T> T[] toArray(T[] old) { 
     T[] arr = Arrays.copyOf(old, old.length + size()); 
     int i = old.length; 
     for(E obj : this) { 
      arr[i] = old.getClass().getComponentType().cast(obj); 
      ++i; 
     } 
     return arr; 
    } 

(请注意,这不符合合同有人指出,通过axtavt。)

我得到这个警告:

Type safety: Unchecked cast from capture#2-of ? to T 

这仍然是实施它的最好/最直接的方法吗?我能以某种方式编写代码而没有发出警告吗?否则我将如何实施?


编辑:我目前的解决方案。首先,我真的不想在toArray本身有这样的警告。因此,我编码(有关这些的进一步讨论read here),这些小助手功能:

@SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T obj) { 
    return (Class<? extends T>) obj.getClass(); 
} 

@SuppressWarnings("unchecked") static <T> Class<? extends T> classOf(T[] array) { 
    return (Class<? extends T>) array.getClass().getComponentType(); 
} 

@SuppressWarnings("unchecked") static <T> T[] newArray(Class<T> clazz, int size) { 
    return (T[]) Array.newInstance(clazz, size); 
} 

现在,我的toArray实现的样子:

public <T> T[] toArray(T[] array) { 
     int size = size(); 
     if (array.length < size) { 
      array = newArray(classOf(array), size); 
     } else if (array.length > size) { 
      array[size] = null; 
     } 

     int i = 0; 
     for (E e : this) { 
      array[i] = classOf(array).cast(e); 
      i++; 
     } 
     return array; 
    } 
+1

你要集合在签名的地方? – 2010-10-24 23:08:33

+0

你所能做的只是转换为(T),而cast()方法只改变引用的类型,它不会改变引用的对象的类型。 – 2010-10-24 23:41:10

回答

8

这仍然是最好/最简单的实现它的方式?否则我将如何实施?

这不是乔希布洛赫如何做的。看看AbstractCollection#toArray()的来源。以下是JDK 1.6.0_22的相关摘录。

public <T> T[] toArray(T[] a) { 
    // Estimate size of array; be prepared to see more or fewer elements 
    int size = size(); 
    T[] r = a.length >= size 
     ? a 
     : (T[]) Array.newInstance(a.getClass().getComponentType(), size); 
    Iterator<E> it = iterator(); 

    for (int i = 0; i < r.length; i++) { 
     if (!it.hasNext()) { // fewer elements than expected 
      if (a != r) 
       return Arrays.copyOf(r, i); 
      r[i] = null; // null-terminate 
      return r; 
     } 
     r[i] = (T) it.next(); 
    } 
    return it.hasNext() ? finishToArray(r, it) : r; 
} 

的源代码是在src.zip文件的JDK可用。您可以将其集成到Eclipse/IDEA/Netbeans等任何像样的IDE中,以便在打开AbstractCollection类时看到它。

我可以以某种方式在没有警告的情况下编码吗?

如果是打扰您,请使用@SuppressWarnings("unchecked")

也就是说,如果可能的话,我建议扩展AbstractCollection而不是实现Collection,这样至少可以实现已经为您实现的基本功能。

4

首先,如果它应该是Collection.toArray()的实现,它不会遵循合约 - 您不应该在数组中保留旧元素(请参阅javadoc)。

的正确实施看起来是这样的:

public <T> T[] toArray(T[] array) { 
    int size = size(); 
    if (array.length < size) { 
     // If array is too small, allocate the new one with the same component type 
     array = Array.newInstance(array.getClass().getComponentType(), size); 
    } else if (array.length > size) { 
     // If array is to large, set the first unassigned element to null 
     array[size] = null; 
    } 

    int i = 0; 
    for (E e: this) { 
     // No need for checked cast - ArrayStoreException will be thrown 
     // if types are incompatible, just as required 
     array[i] = (T) e; 
     i++; 
    } 
    return array; 
} 
+0

啊谢谢你的提示。由于[这](http://stackoverflow.com/questions/4011002/java-eclipse-on-macosx-where-is-the-src-zip),我没有Javadoc可用,并且太懒惰了在线搜索。 :) – Albert 2010-10-24 23:31:02