По какой причине я не могу создать универсальные типы массивов в Java? - PullRequest
254 голосов
/ 28 мая 2010

В чем причина, почему Java не позволяет нам делать

private T[] elements = new T[initialCapacity];

Я мог понять, что .NET не позволил нам сделать это, поскольку в .NET у вас есть типы значений, которые во время выполнения могут иметь разные размеры, но в Java все виды T будут ссылками на объекты, таким образом, имея того же размера (поправьте меня, если я ошибаюсь).

В чем причина?

Ответы [ 15 ]

1 голос
/ 21 ноября 2013

Я знаю, что немного опоздал на вечеринку, но решил, что смогу помочь любым будущим гуглерам, так как ни один из этих ответов не решил мою проблему. Ответ Ferdi265 очень помог, хотя.

Я пытаюсь создать свой собственный связанный список, поэтому следующий код мне подходит:

package myList;
import java.lang.reflect.Array;

public class MyList<TYPE>  {

    private Node<TYPE> header = null;

    public void clear() {   header = null;  }

    public void add(TYPE t) {   header = new Node<TYPE>(t,header);    }

    public TYPE get(int position) {  return getNode(position).getObject();  }

    @SuppressWarnings("unchecked")
    public TYPE[] toArray() {       
        TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());        
        for(int i=0 ; i<size() ; i++)   result[i] = get(i); 
        return result;
    }


    public int size(){
         int i = 0;   
         Node<TYPE> current = header;
         while(current != null) {   
           current = current.getNext();
           i++;
        }
        return i;
    }  

В методе toArray () лежит способ создания массива универсального типа для меня:

TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());    
0 голосов
/ 12 марта 2019

Как уже упоминалось, вы можете, конечно, создать с помощью некоторые трюки .

Но это не рекомендуется.

Поскольку стирание типа и, что более важно, массив covariance in, который только позволяет массиву подтипа, может быть назначен массиву супертипа, что заставляет вас использовать явное приведение типа при попытке получить значение возвращение, вызывающее время выполнения ClassCastException, которое является одной из основных задач, которые непатентованные средства пытаются устранить: Более строгие проверки типов во время компиляции .

Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException

Более прямой пример можно найти в Effective Java: Item 25 .


ковариация : массив типа S [] является подтипом T [], если S является подтипом T

0 голосов
/ 27 мая 2015

Если мы не можем создать экземпляры универсальных массивов, почему язык имеет универсальные типы массивов? Какой смысл иметь тип без объектов?

Единственная причина, о которой я могу думать, это varargs - foo(T...). В противном случае они могли бы полностью очистить универсальные типы массивов. (Ну, им действительно не нужно было использовать массив для varargs, поскольку varargs не существовало до 1.5 . Это, вероятно, еще одна ошибка.)

Так что это ложь, вы можете создавать экземпляры универсальных массивов через varargs!

Конечно, проблемы с универсальными массивами все еще существуют, например,

static <T> T[] foo(T... args){
    return args;
}
static <T> T[] foo2(T a1, T a2){
    return foo(a1, a2);
}

public static void main(String[] args){
    String[] x2 = foo2("a", "b"); // heap pollution!
}

Мы можем использовать этот пример для демонстрации опасности универсального массива.

С другой стороны, мы использовали общие varargs в течение десятилетия, и небо еще не падает. Таким образом, мы можем утверждать, что проблемы преувеличены; Это не важно. Если разрешено явное создание универсального массива, здесь и там будут ошибки; но мы привыкли к проблемам стирания, и мы можем жить с этим.

И мы можем указать на foo2, чтобы опровергнуть утверждение о том, что спецификация защищает нас от проблем, от которых, по их утверждениям, они не хотят. Если бы у Sun было больше времени и ресурсов для 1,5 , я считаю, что они могли бы достичь более удовлетворительного решения.

0 голосов
/ 28 января 2015

Это потому, что дженерики были добавлены в java после того, как они его сделали, поэтому это немного неуклюже, потому что первоначальные создатели java думали, что при создании массива тип будет указан при его создании. Так что это не работает с генериками, поэтому вы должны сделать E [] array = (E []) new Object [15]; Это компилируется, но выдает предупреждение.

0 голосов
/ 23 ноября 2011

Безусловно, должен быть хороший способ обойти это (возможно, с помощью отражения), потому что мне кажется, что именно это и делает ArrayList.toArray(T[] a). Я цитирую:

public <T> T[] toArray(T[] a)

Возвращает массив, содержащий все элементы в этом списке в правильном порядке; тип времени выполнения возвращенный массив - это указанный массив. Если список вписывается в указанный массив, он возвращается в нем. В противном случае новый массив выделяется с типом времени выполнения указанного массива и размером этот список.

Таким образом, одним из способов было бы использовать эту функцию, то есть создать ArrayList объектов, которые вы хотите в массиве, а затем использовать toArray(T[] a) для создания фактического массива. Это не было бы быстро, но вы не упомянули свои требования.

Так кто-нибудь знает, как реализован toArray(T[] a)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...