2013-02-13 3 views
2

У меня есть следующий код, который объединяет два массива и должен обрабатывать любые типы, кроме примитивов.Java создать массив из общего типа времени выполнения другого массива

@SuppressWarnings("unchecked") 
public static synchronized <E> E[] aryMergeNoDup(E[]... arys){ 
    HashSet<E> hs = new HashSet<E>(); 
     for(E[] ary : arys) { 
      if(ary == null) continue; 
      for(E item : ary) { 
       if(item != null) hs.add(item); 
      } 
     } 
     hs.remove(null); 
     return hs.toArray((E[]) Array.newInstance(
       arys.getClass().getComponentType(),hs.size())); 
} 

Однако при выполнении кода он генерирует это исключение:

java.lang.ArrayStoreException: java.lang.String 
    at java.util.AbstractCollection.toArray(AbstractCollection.java:188) 
    at util.Utils.aryMergeNoDup(Utils.java:197) 

Тип выполнения переменной arys является String []; однако, когда я заменяю arys.getClass().getComponentType() кодом String.class, код работает нормально.

Однако этот метод может использоваться только для строк, потому что это pf. Я не вижу, что происходит неправильно, так как они должны ссылаться на java.lang.String.

Строка в AbstractCollection.java:188, что бросает исключение составляет:

r[i] = (T)it.next(); 

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[])java.lang.reflect.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; 
} 

ответ

3

Поскольку это varargs, тип времени работы arys будет E[][], а не E[]. Поэтому вам, вероятно, понадобится arys.getClass().getComponentType().getComponentType() в качестве аргумента Array.newInstance.

+0

arys.getClass(). GetComponentType(). GetComponentType() работает с удовольствием! – user1467885

0

Я считаю, что проблема в том, что arys является то, как массив массивов. Так, вероятно, arys.getClass().getComponentType() is String[], а не String.

0

У вас есть две отдельные вещи, взаимодействующие здесь. Во-первых, вы используете varargs, которые под обложками переносят свои аргументы в массив, создаваемый «на лету». Таким образом, тип arys будет E [] [], поэтому получить тип компонента будет E []. Во-вторых, дженерики означают, что E стирается до Object во время выполнения, поэтому даже два вызова getComponentType не собираются его обрезать, если только вы не уверены, что всегда возвращаете Object [].

Что вы можете сделать, это использовать компонентный тип arys [0], если он существует. Это не будет работать даже во всех случаях, поскольку, например, тип второго массива может быть суперклассом или родственным первым, несовместимым с массивом первого типа.

Чтобы решить эту проблему, вы можете рассчитать наименьший тип верхней границы, изучив типы всех массивов, но я думаю, что это чрезмерное по сравнению с «победами первого типа», если ваше типичное использование будет массивами того же типа.

+0

«Во-вторых, дженерики означают, что E стирается до Object во время выполнения, поэтому даже два вызова getComponentType не собираются его обрезать, если только вы не в порядке, всегда возвращаете Object []." Это не имеет смысла. Тип 'arys' -' E [] [] ', что означает, что тип времени выполнения' arys', если не 'null', гарантированно будет' E [] [] 'или подтипом, если вы ничего не сделали где-то небезопасно. – newacct

+0

Конечно. Я сказал, что «E» удаляется во время выполнения до «Object», а не «E [] []» стирается во время выполнения до «Object». Точка в том, что вы не сможете использовать 'arys.getComponentType(). GetComponentType()', чтобы определить тип E, а не тип времени выполнения переданных массивов. – BeeOnRope

+0

ОК, вы правы - тип времени исполнения массива varargs, по-видимому, выбирается на основе типов времени компиляции переданных объектов - я думал, что это всегда будет Object [] []. Итак, 'getComponentType(). GetComponentType()' будет отображать этот выбор времени компиляции. Использование типов (типов) элементов по-прежнему будет выбирать более конкретный тип массива, когда типы времени компиляции массивов на сайте вызова не равны их наиболее производным типам времени выполнения. – BeeOnRope

Смежные вопросы