Общие массивы в Java
Хорошо, я занимаюсь поиском в Интернете, и я просто не могу найти решение моей проблемы. Я нашел множество решений, просто не подходящих.
Мне нужно создать массив дженериков. Но сам общий тип расширяет Comparable. Когда я попробую следующее:
public class Hash<T extends Comparable> { private T[] hashTable; private int tableSize; Hash(int records, double load) { tableSize = (int)(records / loadFactor); tableSize = findNextPrime(tableSize); hashTable = (T[])(new Object[tableSize]); //Error: Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable; } }
Проблема в том, что объект нельзя отличить как общий, который расширяет Comparable. Есть ли способ обойти это?
- Создать ArrayList из массива
- Сортировка двух NSArrays вместе бок о бок
- Как получить String Array из файла arrays.xml
- Загрузка нескольких файлов (массив) с помощью CodeIgniter 2.0
- Каков максимальный размер, который может содержать массив?
- Использование malloc для размещения многомерных массивов с разной длиной строк
- Возможно ли динамическое построение многомерного массива в Java?
- Преобразование NSArray в NSString в Objective-C
- JavaScript - почему Array.prototype.fill фактически заполняет «указатель» объекта при заполнении чего-либо типа «новый объект ()»
- Определите, является ли JSON JSONObject или JSONArray
- Как получить срез в виде массива в Rust?
- Любой более быстрый способ копирования массивов в C #?
- Самый быстрый алгоритм для массива размера круга N для M позиции
В общем случае генераторы и массивы не смешиваются. Короткий ответ заключается в том, что вы можете обойти эту проблему. Более длинный ответ заключается в том, что вы, вероятно, не должны, и я объясню, почему.
Вы можете использовать Array.newInstance()
следующим образом:
private Comparable[] hashtable; ... hashtable = (Comparable[])Array.newInstance(Comparable.class, tableSize);
но вы не можете создать массив вашего параметризованного типа.
Массивы ковариантны . Это означает, что они сохраняют тип своих элементов во время выполнения. Генералов Java нет. Они используют стирание типа, чтобы в основном замаскировать неявное литье, которое происходит. Это важно понять.
Поэтому, когда вы создаете массив Object, вы не можете использовать его, скажем, для массива Comparable (или любого другого типа), потому что это неверно.
Чтобы привести пример. С дженериками это совершенно законно:
List list = new ArrayList (); List list2 = (List )list; list.add(3);
Вот почему вы не можете этого сделать:
public T newInstance(T t) { return new T(); // error! }
т.е. во время выполнения нет знаний о classе Т. Вот почему приведенный выше код чаще всего записывается как:
public T newInstance(T t, Class clazz) { return clazz.newInstance(); }
потому что их нет типа времени выполнения для общего аргумента. Но с массивами:
String arr[] = new String[10]; Integer arr2[] = (Integer[])arr; // error!
То, что вы должны делать в этом случае (imho), не использует массивы, а использует ArrayList
. Честно говоря, очень мало оснований для использования массивов над ArrayList
и дженерики – всего лишь один пример этого.
Для лучшего и более полного объяснения см. (Отличные) часто задаваемые вопросы Java Generics :
Могу ли я создать массив, тип компонента которого является конкретным параметризованным типом?
Нет, потому что это не безопасно.
Массивы являются ковариантными, что означает, что массив ссылок на супертипы является супертипом массива ссылок подтипов. То есть
Object[]
является супертипомString[]
и массив строк можно получить через ссылочную переменную типаObject[]
.…
Другие ответы здесь, как правило, все выступают за лучший подход к этому (особенно рекомендация использовать ArrayList вместо этого), но простой ответ в этом конкретном случае может заключаться в следующем:
hashTable = (T[])(new Comparable[tableSize]);
(т. е. создать массив типа raw Comparable вместо Object)
Если вы правильно инкапсулируете весь доступ к этому массиву внутри вашего объекта Hash, это должно работать, но (как объясняют другие ответы) вы можете оставить себя уязвимыми.
Приведение, которое вы пытаетесь
(T[])(new Object[tableSize]);
fail, потому что элементы в массиве являются экземплярами Object. Объект не расширяет Comparable
, поэтому приведение (T []) не выполняется, поскольку T определяется как:
T extends Comparable
Чтобы решить эту проблему, выполните следующие действия:
- Создайте массив таким образом, чтобы его элементы были экземплярами некоторого classа, которые расширяют
Comparable
- Измените
hashTable
из массива (который не является общим типом), в общий тип коллекции, напримерList
hashTable = new ArrayList (tableSize>)
Вы часто сталкиваетесь с проблемами, когда вам нужно создать экземпляр какого-то родового типа. Самый простой способ обойти это – передать class, который фактически будет храниться в конструкторе. Таким образом, вы можете построить из фактического типа. Попробуйте что-то вроде этого:
public class Hash> { Hash(int records, double load, Class class) { tableSize = (int)(records / loadFactor); tableSize = findNextPrime(tableSize); hashTable = java.lang.reflect.Array.newInstance(class, tableSize); } private T[] hashTable; private int tableSize; }
Принудительный бросок, предложенный другими людьми, не работал для меня, бросая исключение из незаконного литья.
Однако этот неявный бросок отлично работал:
Item[] array = new Item[SIZE];
где Item – это class I, содержащий член:
private K value;
Таким образом вы получите массив типа K (если элемент имеет только значение) или любой общий тип, который вы хотите определить в элементе classа.