Kann kein Array von LinkedLists in Java erstellen ...?

102

Ich arbeite an einer Sparse - Matrix - Klasse , die benötigt ein Array von verwenden , um LinkedListdie Werte einer Matrix zu speichern. Jedes Element des Arrays (dh jedes LinkedList) repräsentiert eine Zeile der Matrix. Und jedes Element im LinkedListArray repräsentiert eine Spalte und den gespeicherten Wert.

In meiner Klasse habe ich eine Deklaration des Arrays als:

private LinkedList<IntegerNode>[] myMatrix;

Und in meinem Konstruktor für SparseMatrixversuche ich zu definieren:

myMatrix = new LinkedList<IntegerNode>[numRows];

Der Fehler, den ich am Ende bekomme, ist

Es kann kein generisches Array von erstellt werden LinkedList<IntegerNode>.

Ich habe also zwei Probleme damit:

  1. Was mache ich falsch und
  2. Warum ist der Typ in der Deklaration für das Array akzeptabel, wenn er nicht erstellt werden kann?

IntegerNodeist eine Klasse, die ich erstellt habe. Und alle meine Klassendateien sind zusammen gepackt.

Kafuchau
quelle

Antworten:

64

Sie können keine generische Array-Erstellung verwenden. Es ist ein Fehler / Merkmal von Java-Generika.

Die Wege ohne Warnungen sind:

  1. Verwenden der Listenliste anstelle des Listenarrays:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
  2. Deklarieren der speziellen Klasse für Array of Lists:

    class IntegerNodeList {
        private final List< IntegerNode > nodes;
    }
    
Sergey
quelle
19
Eine bessere Alternative zu letzterer Lösung wäre: class IntegerNodeList extends List<IntegerNode> {}
Kamasheto
Diese Implementierung ist unverschämt langsam. Wenn Sie das Element [1000] [2000] (nodeLists.get (1000) .get (2000)) abrufen, wird LinkedList 3000 Mal iteriert! Vermeiden Sie LinkedList, wenn jemand darauf indiziert. ArrayList indiziert schneller, aber die Lösung von Fredrik ist insgesamt besser.
Steve Zobell
142

Aus irgendeinem Grund müssen Sie den Typ umwandeln und die Deklaration wie folgt abgeben:

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList<?>[numRows];
Fredrik
quelle
Ich habe ein ähnliches Problem untersucht und gelesen, dass die obige Besetzung ein sehr häufiger "Hack" ist, der im gesamten Sammlungs-Framework verwendet wird.
Luke
15
IMO, dies sollte die ausgewählte Antwort sein. Ich habe noch nicht experimentiert, aber ich habe das Gefühl, dass Sergeys Methode Nr. 2 ziemlich viel Aufwand verursacht. und ich bin POSITIV, dass # 1 tut. Eine Liste ist in mehrfacher Hinsicht nicht so effizient wie ein Array, was ich hier nicht näher erläutere, aber ich habe Experimente durchgeführt und bei der Verwendung von Listen im Vergleich zu Arrays große Verlangsamungen festgestellt. Es ist schneller, nur Ihre eigenen Arrays zu verwalten und neu zuzuweisen, als Dinge zu einer Liste hinzuzufügen.
Ricket
@Ricket Ich stimme zu, entnommen aus ibm.com/developerworks/java/library/j-jtp01255/index.html
Peteter
4
Ich erhalte immer noch die Warnung "Typensicherheit: ungeprüfte Besetzung". Bobs Lösung sieht für mich am saubersten aus.
Marco Lackovic
3
In JDK 7 gibt das Obige eine Warnung zu Rohtypen aus. Das kann mit dem unbegrenzten <?> Typ behoben werden, aber Sie erhalten immer noch eine ungeprüfte Warnung (die unterdrückt werden kann). zB <br> <code> myMatrix = (LinkedList <IntegerNode> []) neue LinkedList <?> [numRows]; </ code>
Neon
5

Abgesehen von den Syntaxproblemen erscheint es mir seltsam, ein Array und eine verknüpfte Liste zur Darstellung einer Matrix zu verwenden. Um auf beliebige Zellen der Matrix zugreifen zu können, möchten Sie wahrscheinlich, dass ein tatsächliches Array oder zumindest ein ArrayListdie Zeilen enthält, da LinkedListdie gesamte Liste vom ersten Element zu einem bestimmten Element, einer O(n)Operation, durchlaufen werden muss , im Gegensatz zu viel schneller O(1)mit ArrayListoder einem tatsächlichen Array.

Da Sie erwähnt haben, dass diese Matrix spärlich ist, können Sie die Daten möglicherweise besser als Karte mit Karten speichern, wobei ein Schlüssel in der ersten Karte einen Zeilenindex darstellt und sein Wert eine Zeilenzuordnung ist, deren Schlüssel ein Spaltenindex sind , wobei der Wert Ihre IntegerNode-Klasse ist. So:

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

Wenn Sie in der Lage sein müssen, die Matrix zeilenweise zu durchlaufen, können Sie den Zeilenzuordnungstyp a festlegen TreeMap, und dasselbe gilt für das Durchlaufen der Spalten in Indexreihenfolge. Wenn Sie diese Fälle jedoch nicht benötigen, HashMapist dies schneller als TreeMap. Hilfsmethoden zum Abrufen und Festlegen einer beliebigen Zelle, die nicht festgelegte Nullwerte verarbeiten, wären natürlich nützlich.

Dov Wasserman
quelle
4
class IntegerNodeList extends LinkedList<IntegerNode> {}

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 
Bob
quelle
Sie haben die Generika für LinkedList verpasst.
Peter Wippermann
3

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

Das Casting auf diese Weise funktioniert, hinterlässt aber dennoch eine böse Warnung:

"Typensicherheit: Der Ausdruck vom Typ Liste [] muss deaktiviert konvertiert werden."

Deklarieren einer speziellen Klasse für Array of Lists:

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

ist eine clevere Idee, um die Warnung zu vermeiden. Vielleicht ist es ein bisschen schöner, eine Schnittstelle dafür zu verwenden:

public interface IntegerNodeList extends List<IntegerNode> {}

dann

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

Kompiliert ohne Warnungen.

sieht nicht schlecht aus, oder?

user306708
quelle
IntegerNodeList: Mit welcher Klasse würden Sie dies verwenden? Beispielsweise konnten Sie ihm keine ArrayList <IntegerNode> zuweisen. Sie müssten auch ArrayList erweitern ...
Hans-Peter Störr
Die Schnittstelle IntegerNodeList muss nicht außerhalb der Initialisierung des Arrays verwendet werden: List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; for (int i = 0; i <myMatrix.length; i ++) {myMatrix [i] = new ArrayList <IntegerNode> (); }
user306708
1
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];Dies hat ein subtiles, aber wichtiges Problem. Sie können nur setzen IntegerNodeListin der Anordnung. myMatrix[i] = new ArrayList<IntegerNode>();wird werfen ArrayStoreException.
Radiodef
2
List<String>[] lst = new List[2];
lst[0] = new LinkedList<String>();
lst[1] = new LinkedList<String>();

Keine Warnungen. NetBeans 6.9.1, jdk1.6.0_24

Andrii
quelle
1
Richtig, keine Warnungen, aber mit Java SE 6 Update 32 von Oracle wird der Kompilierungsfehler "Der Typ List ist nicht generisch; er kann nicht mit Argumenten <String> parametrisiert werden" angezeigt. Das Entfernen des Arguments <String> führt zu einem weiteren Fehler "Typkonflikt: Konvertierung von LinkedList <String> in Liste nicht möglich".
Marco Lackovic
0

Wenn ich Folgendes tue, wird die betreffende Fehlermeldung angezeigt

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

Aber wenn ich nur den Listentyp in der Deklaration entferne, scheint er die gewünschte Funktionalität zu haben.

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

Unterscheiden sich diese beiden Erklärungen drastisch, was mir nicht bewusst ist?

BEARBEITEN

Ah, ich glaube, ich bin jetzt auf dieses Problem gestoßen.

Das Iterieren über die Matrix und das Initialisieren der Listen in einer for-Schleife scheint zu funktionieren. Obwohl es nicht so ideal ist wie einige der anderen angebotenen Lösungen.

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

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

Sie benötigen eine Reihe von Listen. Eine Alternative besteht darin, Folgendes zu versuchen:

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

Dann node_array[i]speichert den Kopf (ersten) Knoten ein ArrayList<IntegerNode>oder LinkedList<IntegerNode>(was auch immer Ihre Favoritenliste Implementierung).

Bei diesem Entwurf verlieren Sie die Direktzugriffsmethode list.get(index), können dann jedoch die Liste beginnend mit dem Kopf- / Faustknotenspeicher im Typ-Safe-Array durchlaufen.

Dies kann je nach Anwendungsfall eine akzeptable Designwahl sein. Zum Beispiel verwende ich dieses Design, um eine Adjazenzliste eines Diagramms darzustellen. In den meisten Anwendungsfällen muss die Adjazenzliste ohnehin für einen bestimmten Scheitelpunkt durchlaufen werden, anstatt zufällig auf einen Scheitelpunkt in der Liste zuzugreifen.

Yiling
quelle