Impossible de créer un tableau de LinkedLists en Java…?

102

Je travaille sur une classe de matrice clairsemée qui doit utiliser un tableau de LinkedListpour stocker les valeurs d'une matrice. Chaque élément du tableau (c'est-à-dire chacun LinkedList) représente une ligne de la matrice. Et, chaque élément du LinkedListtableau représente une colonne et la valeur stockée.

Dans ma classe, j'ai une déclaration du tableau comme:

private LinkedList<IntegerNode>[] myMatrix;

Et, dans mon constructeur pour le SparseMatrix, j'essaye de définir:

myMatrix = new LinkedList<IntegerNode>[numRows];

L'erreur que je finis par obtenir est

Impossible de créer un tableau générique de LinkedList<IntegerNode>.

Donc, j'ai deux problèmes avec ceci:

  1. Qu'est-ce que je fais de mal, et
  2. Pourquoi le type est-il acceptable dans la déclaration du tableau s'il ne peut pas être créé?

IntegerNodeest une classe que j'ai créée. Et, tous mes fichiers de classe sont emballés ensemble.

kafuchau
la source

Réponses:

64

Vous ne pouvez pas utiliser la création de tableau générique. C'est une faille / fonctionnalité des génériques Java.

Les moyens sans avertissements sont:

  1. Utilisation de la liste de listes au lieu du tableau de listes:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
  2. Déclarer la classe spéciale pour Array of Lists:

    class IntegerNodeList {
        private final List< IntegerNode > nodes;
    }
Sergey
la source
19
Une meilleure alternative à cette dernière solution serait de: class IntegerNodeList extends List<IntegerNode> {}
kamasheto
Cette mise en œuvre est extrêmement lente. Obtenir l'élément [1000] [2000] (nodeLists.get (1000) .get (2000)) fera que LinkedList itérera 3000 fois! Évitez LinkedList si quelqu'un peut y être indexé. ArrayList indexera plus rapidement, mais la solution de Fredrik est globalement meilleure.
Steve Zobell
142

Pour une raison quelconque, vous devez convertir le type et faire la déclaration comme ceci:

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList<?>[numRows];
Fredrik
la source
J'ai recherché un problème similaire et j'ai lu que la distribution ci-dessus est un «hack» très courant qui est utilisé dans tout le cadre des collections.
lu
15
OMI, cela devrait être la réponse choisie. Je n'ai pas expérimenté, mais j'ai le sentiment instinctif que la méthode n ° 2 de Sergey crée pas mal de frais généraux; et je suis POSITIF que # 1 le fasse. Une liste n'est pas aussi efficace qu'un tableau de plusieurs manières que je ne détaillerai pas ici, mais J'AI fait des expériences et vu de gros ralentissements lors de l'utilisation de listes par rapport à des tableaux. Il est plus rapide de simplement gérer vos propres tableaux et de les réattribuer, que d'ajouter des éléments à une liste.
Ricket
@Ricket Je suis d'accord, extrait de ibm.com/developerworks/java/library/j-jtp01255/index.html
Peteter
4
Je reçois toujours un avertissement "Sécurité de type: diffusion non vérifiée". La solution de Bob me semble la plus propre.
Marco Lackovic
3
Dans JDK 7, ce qui précède donne un avertissement de rawtypes. Cela peut être corrigé en utilisant le type illimité <?>, Mais vous obtenez toujours un avertissement non vérifié (qui peut être supprimé). par exemple <br> <code> myMatrix = (LinkedList <IntegerNode> []) new LinkedList <?> [numRows]; </code>
Neon
5

Mis à part les problèmes de syntaxe, il me semble étrange d'utiliser un tableau et une liste chaînée pour représenter une matrice. Pour pouvoir accéder à des cellules arbitraires de la matrice, vous voudrez probablement qu'un tableau réel ou au moins un ArrayListcontienne les lignes, car il LinkedListdoit parcourir toute la liste du premier élément à un élément particulier, une O(n)opération, par opposition à beaucoup plus rapide O(1)avec ArrayListou un tableau réel.

Puisque vous avez mentionné que cette matrice est clairsemée, cependant, la meilleure façon de stocker les données est peut-être sous la forme d'une carte de cartes, où une clé dans la première carte représente un index de ligne et sa valeur est une carte de ligne dont les clés sont un index de colonne , la valeur étant votre classe IntegerNode. Donc:

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

Si vous avez besoin de pouvoir parcourir la matrice ligne par ligne, vous pouvez faire en sorte que le mappage de ligne soit de type a TreeMap, et de même pour parcourir les colonnes dans l'ordre d'index, mais si vous n'avez pas besoin de ces cas, HashMapc'est plus rapide que TreeMap. Des méthodes d'aide pour obtenir et définir une cellule arbitraire, gérant des valeurs nulles non définies, seraient bien sûr utiles.

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

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 
Bob
la source
Vous avez manqué les génériques pour LinkedList.
Peter Wippermann
3

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

le casting de cette façon fonctionne mais vous laisse toujours un mauvais avertissement:

"Sécurité de type: l'expression de type List [] nécessite une conversion non cochée."

Déclarer une classe spéciale pour Array of Lists:

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

est une idée intelligente pour éviter l'avertissement. peut-être un peu plus agréable est d'utiliser une interface pour cela:

public interface IntegerNodeList extends List<IntegerNode> {}

puis

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

compile sans avertissement.

n'a pas l'air trop mal, n'est-ce pas?

utilisateur306708
la source
IntegerNodeList: avec quelle classe utiliseriez-vous cela? Par exemple, vous ne pouvez pas lui attribuer un ArrayList <IntegerNode>. Vous devrez également étendre ArrayList ...
Hans-Peter Störr
il n'est pas nécessaire d'utiliser l'interface IntegerNodeList en dehors de l'initialisation du tableau: 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];Cela pose un problème subtil mais important. Vous pouvez ne mettre IntegerNodeListdans le tableau. myMatrix[i] = new ArrayList<IntegerNode>();jettera ArrayStoreException.
Radiodef
2
List<String>[] lst = new List[2];
lst[0] = new LinkedList<String>();
lst[1] = new LinkedList<String>();

Aucun avertissement. NetBeans 6.9.1, jdk1.6.0_24

Andrii
la source
1
Vrai pas d'avertissement mais avec la mise à jour 32 de Java SE 6 d'Oracle, j'obtiens l'erreur de compilation "Le type List n'est pas générique; il ne peut pas être paramétré avec des arguments <String>". La suppression de l'argument <String> génère une autre erreur "Incompatibilité de type: impossible de convertir de LinkedList <String> en liste".
Marco Lackovic
0

Si je fais ce qui suit, j'obtiens le message d'erreur en question

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

Mais si je supprime simplement le type de liste dans la déclaration, il semble avoir la fonctionnalité souhaitée.

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

Ces deux déclarations sont-elles radicalement différentes d'une manière dont je ne suis pas au courant?

ÉDITER

Ah, je pense que j'ai rencontré ce problème maintenant.

Itérer sur la matrice et initialiser les listes dans une boucle for semble fonctionner. Bien que ce ne soit pas aussi idéal que certaines des autres solutions proposées.

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

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

Vous avez besoin d'un tableau de List, une alternative est d'essayer:

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

node_array[i]Stocke ensuite le nœud principal (premier) d'un ArrayList<IntegerNode>ou LinkedList<IntegerNode>(quelle que soit votre implémentation de liste préférée).

Dans cette conception, vous perdez la méthode d'accès aléatoire list.get(index), mais vous pouvez toujours parcourir la liste en commençant par le magasin de nœuds head / fist dans le tableau de type sécurisé.

Cela peut être un choix de conception acceptable en fonction de votre cas d'utilisation. Par exemple, j'utilise cette conception pour représenter une liste de graphes de contiguïté, dans la plupart des cas d'utilisation, il faut de toute façon traverser la liste de contiguïté pour un sommet donné au lieu d'accéder au hasard à un sommet de la liste.

Yiling
la source