Java: как реализовать "toArray" для " коллекции`
прямо сейчас у меня:
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
это все еще лучший / самый простой способ его реализации? Могу ли я каким-то образом закодировать его без этого предупреждения? Иначе как бы я его реализовал?
Edit: мое текущее решение. Во-первых, я очень хотел не иметь такого предупреждения в . Следовательно, Я закодировал эти маленькие вспомогательные функции (читать здесь для дальнейшего обсуждения этих):
@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;
}
2 ответов
это все еще лучший / самый простой способ его реализации? Иначе как бы я его реализовал?
это не так, как сделал Джош блох. Взгляните на источник 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. Вы можете интегрировать его в любую приличную IDE, такую как Eclipse/IDEA/Netbeans, чтобы вы могли видеть его при открытии AbstractCollection
класс.
можно ли как-то код так, без предупреждения?
нет. Использовать @SuppressWarnings("unchecked")
если это беспокоит вас.
тем не менее, я бы предложил продлить AbstractCollection
вместо реализации Collection
если это возможно, так что у вас есть хотя бы базовые функции уже реализованы для вас.
прежде всего, если это должна быть реализация 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;
}