2010-10-24 20 views
7

En este momento, no tengo:Java: cómo implementar `` toArray` para 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; 
    } 

(Tenga en cuenta que esto no se sigue el contrato como se señaló por axtavt.)

donde consigo esta advertencia:

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

¿sigue siendo la mejor manera/más directa para implementarla? ¿Puedo de alguna manera codificarlo de una manera sin esa advertencia? ¿Cómo lo implementaría de otra manera?


Editar: Mi solución actual. Primero, realmente quería no tener esa advertencia en el toArray. Por lo tanto, codifiqué estas funciones poco cooperadoras (read here para una mayor discusión sobre estos):

@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); 
} 

Ahora, mi toArray aplicación se parece a:

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

¿Quieres una colección en la firma en alguna parte? –

+0

Todo lo que puede hacer es convertirlo a (T), el método de conversión() solo cambia el tipo de referencia, no cambiará el tipo de objeto al que se hace referencia. –

Respuesta

8

¿Sigue siendo el mejor/más directa forma de implementarlo? ¿Cómo lo implementaría de otra manera?

No fue así como lo hizo Josh Bloch. Eche un vistazo a la fuente de AbstractCollection#toArray(). Aquí hay un extracto de relevancia de 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; 
} 

El código fuente está disponible en src.zip archivo del JDK. Puede integrarlo en cualquier IDE decente como Eclipse/IDEA/Netbeans para que pueda verlo cuando abre la clase AbstractCollection.

¿Puedo de alguna manera codificarlo de una manera sin esa advertencia?

No. Utilice @SuppressWarnings("unchecked") si le molesta.

Dicho esto, sugiero ampliar AbstractCollection en lugar de implementar Collection si es posible para que tenga al menos las funciones básicas ya implementadas para usted.

4

En primer lugar, si se supone que es una implementación de Collection.toArray(), no sigue el contrato; no debe conservar los elementos antiguos en la matriz (consulte javadoc).

La aplicación correcta se parece a esto:

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

Ah gracias por la pista. Debido a [esto] (http://stackoverflow.com/questions/4011002/java-eclipse-on-macosx-where-is-the-src-zip), no tenía el Javadoc disponible y era demasiado flojo para búscalo en línea. :) – Albert