Не удается создать массив LinkedLists в Java ...?

Я работаю над классом разреженной матрицы, который потребности использует массив LinkedList для хранения значений матрицы. Каждый элемент массива (т.е. каждый LinkedList) представляет собой строку матрицы. И каждый элемент в массиве LinkedList представляет столбец и сохраненное значение.

В моем классе у меня есть объявление массива как:

private LinkedList<IntegerNode>[] myMatrix;

И в моем конструкторе для SparseMatrix я пытаюсь определить:

myMatrix = new LinkedList<IntegerNode>[numRows];

Ошибка, которую я получаю, это

Cannot create a generic array of LinkedList<IntegerNode>.

Итак, у меня есть две проблемы:

  1. Что я делаю не так и
  2. Почему тип приемлем в объявлении для массива, если он не может быть создан?

IntegerNode - это созданный мной класс. И все мои файлы классов упакованы вместе.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
103
0
72 822
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

По какой-то причине вам нужно привести тип и сделать объявление следующим образом:

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList<?>[numRows];

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

luke 20.10.2008 16:25

ИМО, это должен быть выбранный ответ. Я не экспериментировал, но мне кажется, что метод Сергея №2 создает довольно много накладных расходов; и я ПОЗИТИВНО, что № 1 делает. Список не так эффективен, как массив, по нескольким причинам, которые я не буду здесь подробно описывать, но я проводил эксперименты и видел большие замедления при использовании списков по сравнению с массивами. Быстрее просто управлять своими собственными массивами и перераспределять их, чем добавлять что-то в список.

Ricket 30.07.2009 20:02

@Ricket Согласен, взято из ibm.com/developerworks/java/library/j-jtp01255/index.html

Peteter 01.08.2011 19:39

Я по-прежнему получаю предупреждение "Типовая безопасность: непроверенное приведение". Решение Боба мне кажется самым чистым.

Marco Lackovic 23.05.2012 21:28

@Krige, вы ничего не можете с этим поделать, потому что является не отмечен, отсюда и предупреждение. И я бы не сказал, что написание совершенно нового класса обязательно является «более чистым» решением; особенно если мы говорим об накладных расходах.

b1nary.atr0phy 15.09.2012 06:32

В JDK 7 приведенное выше дает предупреждение rawtypes. Это можно исправить с помощью неограниченного типа <?>, Но вы все равно получите непроверенное предупреждение (которое можно подавить). например <br> <code> myMatrix = (LinkedList <IntegerNode> []) новый LinkedList <?> [numRows]; </code>

Neon 04.01.2013 18:28

Это лучшее решение. И я считаю, что это недостаток Java.

sudo 17.04.2015 08:29

Я думаю, что принятый ответ - лучший ответ, но мне нравится ваш ответ. Жаль, что для Generics и массивов требуются такие инновации.

Mushy 14.09.2017 17:43

В Java 1.5 (или 1.6, насколько я могу судить) нет универсального создания массива. См. https://community.oracle.com/message/4829402.

Ответ принят как подходящий

Вы не можете использовать создание универсального массива. Это недостаток / особенность дженериков Java.

Способы без предупреждений:

  1. Использование списка списков вместо массива списков:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
    
  2. Объявление специального класса для массива списков:

    class IntegerNodeList {
        private final List< IntegerNode > nodes;
    }
    

Лучшей альтернативой последнему решению было бы: class IntegerNodeList extends List<IntegerNode> {}

kamasheto 19.04.2010 01:45

Эта реализация возмутительно медленная. При получении элемента [1000] [2000] (nodeLists.get (1000) .get (2000)) LinkedList будет повторяться 3000 раз! Избегайте LinkedList, если кто-то может индексировать его. ArrayList будет индексировать быстрее, но решение Фредрика в целом лучше.

Steve Zobell 09.03.2017 23:08

Помимо проблем с синтаксисом, мне кажется странным использовать массив и связанный список для представления матрицы. Чтобы иметь возможность доступа к произвольным ячейкам матрицы, вам, вероятно, понадобится фактический массив или, по крайней мере, ArrayList для хранения строк, поскольку LinkedList должен пройти весь список от первого элемента до любого конкретного элемента, операция O(n), в отличие от к гораздо более быстрому O(1) с ArrayList или реальным массивом.

Поскольку вы упомянули, что эта матрица разреженная, возможно, лучший способ хранить данные - это карта карт, где ключ в первой карте представляет индекс строки, а его значение - карта строк, ключи которой являются индексом столбца , со значением вашего класса IntegerNode. Таким образом:

private Map<Integer, Map<Integer, IntegerNode>> myMatrix = new HashMap<Integer, Map<Integer, IntegerNode>>();

// access a matrix cell:
int rowIdx = 100;
int colIdx = 30;
Map<Integer, IntegerNode> row = myMatrix.get(rowIdx); // if null, create and add to matrix
IntegerNode node = row.get(colIdx); // possibly null

Если вам нужно иметь возможность перемещаться по матрице строка за строкой, вы можете сделать тип карты строк TreeMap, и то же самое для обхода столбцов в порядке индекса, но если вам не нужны эти случаи, HashMap быстрее, чем TreeMap. Конечно, были бы полезны вспомогательные методы для получения и установки произвольной ячейки, обрабатывающие неустановленные нулевые значения.

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList[numRows];

приведение такого способа работает, но по-прежнему оставляет вам неприятное предупреждение:

«Безопасность типов: выражение типа List [] требует неконтролируемого преобразования ..»

Declaring a special class for Array of Lists:

class IntegerNodeList { private final List< IntegerNode > nodes; }

это умная идея, чтобы избежать предупреждения. может быть, немного лучше использовать для этого интерфейс:

public interface IntegerNodeList extends List<IntegerNode> {}

потом

List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];

компилируется без предупреждений.

не выглядит так уж плохо, не так ли?

IntegerNodeList: с каким классом вы бы это использовали? Например, вы не могли назначить ему ArrayList <IntegerNode>. Вам также нужно будет расширить ArrayList ...

Hans-Peter Störr 01.04.2010 15:55

нет необходимости использовать интерфейс IntegerNodeList вне инициализации массива: List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; for (int i = 0; i <myMatrix.length; i ++) {myMatrix [i] = new ArrayList <IntegerNode> (); }

user306708 01.04.2010 18:18
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows]; Это тонкая, но важная проблема. Вы можете Только поместить IntegerNodeList в массив. myMatrix[i] = new ArrayList<IntegerNode>(); выбросит ArrayStoreException.
Radiodef 08.04.2015 21:47
class IntegerNodeList extends LinkedList<IntegerNode> {}

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 

Вы пропустили дженерики для LinkedList.

Peter Wippermann 19.12.2012 20:29
List<String>[] lst = new List[2];
lst[0] = new LinkedList<String>();
lst[1] = new LinkedList<String>();

Никаких предупреждений. NetBeans 6.9.1, jdk1.6.0_24

True без предупреждений, но с Oracle Java SE 6 Update 32 я получаю ошибку компиляции «Список типов не является универсальным; его нельзя параметризовать аргументами <String>». Удаление аргумента <String> вызывает другую ошибку «Несоответствие типов: невозможно преобразовать из LinkedList <String> в список».

Marco Lackovic 23.05.2012 18:25

Если я сделаю следующее, я получу соответствующее сообщение об ошибке

LinkedList<Node>[] matrix = new LinkedList<Node>[5];

Но если я просто удалю тип списка в объявлении, он, похоже, будет иметь желаемую функциональность.

LinkedList<Node>[] matrix = new LinkedList[5];

Эти два заявления сильно отличаются друг от друга, о чем я не знаю?

РЕДАКТИРОВАТЬ

Ах, думаю, я столкнулся с этой проблемой сейчас.

Итерация по матрице и инициализация списков в цикле for вроде бы работают. Хотя это не так идеально, как некоторые другие предлагаемые решения.

for(int i=0; i < matrix.length; i++){

    matrix[i] = new LinkedList<>();
}

Вам нужен массив List, одна из альтернатив - попробовать:

private IntegerNode[] node_array = new IntegerNode[sizeOfYourChoice];

Затем node_array[i] сохраняет головной (первый) узел ArrayList<IntegerNode> или LinkedList<IntegerNode> (независимо от вашей любимой реализации списка).

При таком дизайне вы теряете метод произвольного доступа list.get(index), но тогда вы все равно можете перемещаться по списку, начиная с хранилища узлов head / fist в массиве типобезопасности.

Это может быть приемлемым выбором дизайна в зависимости от вашего варианта использования. Например, я использую этот дизайн для представления списка смежности графа, в большинстве случаев использования он требует в любом случае обхода списка смежности для данной вершины вместо произвольного доступа к какой-либо вершине в списке.

Другие вопросы по теме