Я работаю над классом разреженной матрицы, который потребности использует массив LinkedList для хранения значений матрицы. Каждый элемент массива (т.е. каждый LinkedList) представляет собой строку матрицы. И каждый элемент в массиве LinkedList представляет столбец и сохраненное значение.
В моем классе у меня есть объявление массива как:
private LinkedList<IntegerNode>[] myMatrix;
И в моем конструкторе для SparseMatrix я пытаюсь определить:
myMatrix = new LinkedList<IntegerNode>[numRows];
Ошибка, которую я получаю, это
Cannot create a generic array of
LinkedList<IntegerNode>.
Итак, у меня есть две проблемы:
IntegerNode - это созданный мной класс. И все мои файлы классов упакованы вместе.




По какой-то причине вам нужно привести тип и сделать объявление следующим образом:
myMatrix = (LinkedList<IntegerNode>[]) new LinkedList<?>[numRows];
ИМО, это должен быть выбранный ответ. Я не экспериментировал, но мне кажется, что метод Сергея №2 создает довольно много накладных расходов; и я ПОЗИТИВНО, что № 1 делает. Список не так эффективен, как массив, по нескольким причинам, которые я не буду здесь подробно описывать, но я проводил эксперименты и видел большие замедления при использовании списков по сравнению с массивами. Быстрее просто управлять своими собственными массивами и перераспределять их, чем добавлять что-то в список.
@Ricket Согласен, взято из ibm.com/developerworks/java/library/j-jtp01255/index.html
Я по-прежнему получаю предупреждение "Типовая безопасность: непроверенное приведение". Решение Боба мне кажется самым чистым.
@Krige, вы ничего не можете с этим поделать, потому что является не отмечен, отсюда и предупреждение. И я бы не сказал, что написание совершенно нового класса обязательно является «более чистым» решением; особенно если мы говорим об накладных расходах.
В JDK 7 приведенное выше дает предупреждение rawtypes. Это можно исправить с помощью неограниченного типа <?>, Но вы все равно получите непроверенное предупреждение (которое можно подавить). например <br> <code> myMatrix = (LinkedList <IntegerNode> []) новый LinkedList <?> [numRows]; </code>
Это лучшее решение. И я считаю, что это недостаток Java.
Я думаю, что принятый ответ - лучший ответ, но мне нравится ваш ответ. Жаль, что для Generics и массивов требуются такие инновации.
В Java 1.5 (или 1.6, насколько я могу судить) нет универсального создания массива. См. https://community.oracle.com/message/4829402.
Вы не можете использовать создание универсального массива. Это недостаток / особенность дженериков Java.
Способы без предупреждений:
Использование списка списков вместо массива списков:
List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
Объявление специального класса для массива списков:
class IntegerNodeList {
private final List< IntegerNode > nodes;
}
Лучшей альтернативой последнему решению было бы: class IntegerNodeList extends List<IntegerNode> {}
Эта реализация возмутительно медленная. При получении элемента [1000] [2000] (nodeLists.get (1000) .get (2000)) LinkedList будет повторяться 3000 раз! Избегайте LinkedList, если кто-то может индексировать его. ArrayList будет индексировать быстрее, но решение Фредрика в целом лучше.
Помимо проблем с синтаксисом, мне кажется странным использовать массив и связанный список для представления матрицы. Чтобы иметь возможность доступа к произвольным ячейкам матрицы, вам, вероятно, понадобится фактический массив или, по крайней мере, 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 ...
нет необходимости использовать интерфейс IntegerNodeList вне инициализации массива: List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; for (int i = 0; i <myMatrix.length; i ++) {myMatrix [i] = new ArrayList <IntegerNode> (); }
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows]; Это тонкая, но важная проблема. Вы можете Только поместить IntegerNodeList в массив. myMatrix[i] = new ArrayList<IntegerNode>(); выбросит ArrayStoreException.class IntegerNodeList extends LinkedList<IntegerNode> {}
IntegerNodeList[] myMatrix = new IntegerNodeList[numRows];
Вы пропустили дженерики для LinkedList.
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> в список».
Если я сделаю следующее, я получу соответствующее сообщение об ошибке
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 в массиве типобезопасности.
Это может быть приемлемым выбором дизайна в зависимости от вашего варианта использования. Например, я использую этот дизайн для представления списка смежности графа, в большинстве случаев использования он требует в любом случае обхода списка смежности для данной вершины вместо произвольного доступа к какой-либо вершине в списке.
Я исследовал аналогичную проблему и прочитал, что приведенное выше приведение - очень распространенный «взлом», который используется во всей структуре коллекций.