Cannot create an array of LinkedLists in Java…?

2019-01-01 09:15发布

问题:

I\'m working on a sparse matrix class that needs to use an array of LinkedList to store the values of a matrix. Each element of the array (i.e. each LinkedList) represents a row of the matrix. And, each element in the LinkedList array represents a column and the stored value.

In my class, I have a declaration of the array as:

private LinkedList<IntegerNode>[] myMatrix;

And, in my constructor for the SparseMatrix, I try to define:

myMatrix = new LinkedList<IntegerNode>[numRows];

The error I end up getting is

Cannot create a generic array of LinkedList<IntegerNode>.

So, I have two issues with this:

  1. What am I doing wrong, and
  2. Why is the type acceptable in the declaration for the array if it can\'t be created?

IntegerNode is a class that I have created. And, all of my class files are packaged together.

回答1:

You can\'t use generic array creation. It\'s a flaw/ feature of java generics.

The ways without warnings are:

  1. Using List of Lists instead of Array of Lists:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
    
  2. Declaring the special class for Array of Lists:

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


回答2:

For some reason you have to cast the type and make the declaration like this:

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


回答3:

Aside from the syntax issues, it seems strange to me to use an array and a linked list to represent a matrix. To be able to access arbitrary cells of the matrix, you would probably want an actual array or at least an ArrayList to hold the rows, as LinkedList must traverse the whole list from the first element to any particular element, an O(n) operation, as opposed to the much quicker O(1) with ArrayList or an actual array.

Since you mentioned this matrix is sparse, though, perhaps a better way to store the data is as a map of maps, where a key in the first map represents a row index, and its value is a row map whose keys are a column index, with the value being your IntegerNode class. Thus:

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

If you need to be able to traverse the matrix row by row, you can make the row map type a TreeMap, and same for traversing the columns in index order, but if you don\'t need those cases, HashMap is quicker than TreeMap. Helper methods to get and set an arbitrary cell, handling unset null values, would be useful, of course.



回答4:

class IntegerNodeList extends LinkedList<IntegerNode> {}

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 


回答5:

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

casting this way works but still leaves you with a nasty warning:

\"Type safety: The expression of type List[] needs unchecked conversion..\"

Declaring a special class for Array of Lists:

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

is a clever idea to avoid the warning. maybe a little bit nicer is to use an interface for it:

public interface IntegerNodeList extends List<IntegerNode> {}

then

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

compiles without warnings.

doesn\'t look too bad, does it?



回答6:

List<String>[] lst = new List[2];
lst[0] = new LinkedList<String>();
lst[1] = new LinkedList<String>();

No any warnings. NetBeans 6.9.1, jdk1.6.0_24



回答7:

There is no generic array creation in Java 1.5 (or 1.6 as far as I can tell). See https://community.oracle.com/message/4829402.



回答8:

If I do the following I get the error message in question

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

But if I just remove the list type in the declaration it seems to have the desired functionality.

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

Are these two declarations drastically different in a way of which I\'m not aware?

EDIT

Ah, I think I\'ve run into this issue now.

Iterating over the matrix and initializing the lists in a for-loop seems to work. Though it\'s not as ideal as some of the other solutions offered up.

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

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


回答9:

You need an array of List, one alternative is to try:

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

Then node_array[i] stores the head(first) node of a ArrayList<IntegerNode> or LinkedList<IntegerNode> (whatever your favourite list implementation).

Under this design, you lose the random access method list.get(index), but then you could still traverse the list starting with the head/fist node store in the type safe array.

This might be an acceptable design choice depending on your use case. For instance, I use this design to represent an adjacency list of graph, in most use cases, it requires traversing the adjacency list anyway for a given vertex instead of random access some vertex in the list.