JavaでLinkedListsの配列を作成できません…?


102

私は、行列の値を格納するためにの配列を使用する必要がある疎行列クラスに取り組んでいますLinkedList。配列の各要素(つまり、各LinkedList)は、行列の行を表します。また、LinkedList配列の各要素は列と格納された値を表します。

私のクラスでは、配列を次のように宣言しています。

private LinkedList<IntegerNode>[] myMatrix;

そして、のコンストラクターで、以下SparseMatrixを定義しようとします。

myMatrix = new LinkedList<IntegerNode>[numRows];

私が得ることになるエラーは

のジェネリック配列を作成できませんLinkedList<IntegerNode>

したがって、これには2つの問題があります。

  1. 私は何を間違っているのですか、そして
  2. 作成できない配列の宣言で型が受け入れられるのはなぜですか?

IntegerNode私が作成したクラスです。そして、私のクラスファイルはすべて一緒にパッケージ化されています。

回答:


64

ジェネリック配列の作成は使用できません。これは、Javaジェネリックの欠陥/機能です。

警告なしの方法は次のとおりです。

  1. リストの配列の代わりにリストのリストを使用する:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
  2. リストの配列の特別なクラスを宣言する:

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

19
後者の溶液へのより良い代替手段は、になるであろう: class IntegerNodeList extends List<IntegerNode> {}
kamasheto

この実装は法外に遅いです。[1000] [2000]要素(nodeLists.get(1000).get(2000))を取得すると、LinkedListが3000回繰り返されます。誰かがそれにインデックスを付けている可能性がある場合は、LinkedListを避けてください。ArrayListはより高速にインデックスを作成しますが、Fredrikのソリューションは全体的に優れています。
スティーブゾベル2017年

142

何らかの理由で、型をキャストして、次のように宣言する必要があります。

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

私は同様の問題を調査し、上記のキャストがコレクションフレームワーク全体で使用される非常に一般的な「ハック」であることを読みました。
ルーク

15
IMO、これが選択された答えになるはずです。実験はしていませんが、Sergeyの2番目の方法ではかなりのオーバーヘッドが発生するという直感があります。そして、私は#1がそうであると確信しています。リストはいくつかの点で配列ほど効率的ではありませんが、ここでは詳しく説明しませんが、配列と比較してリストを使用すると、実験を行って大幅な速度低下が見られました。リストに要素を追加するよりも、独自の配列を管理して再割り当てする方が高速です。
リケット

私は同意する@Ricket、から取らibm.com/developerworks/java/library/j-jtp01255/index.html
Peteter

4
それでも「タイプセーフ:未チェックのキャスト」という警告が表示されます。ボブのソリューションは私には最もきれいに見えます。
マルコラッコビッチ

3
JDK 7では、上記はrawtypes警告を与えます。これは、無制限の<?>タイプを使用して修正できますが、未チェックの警告が表示されます(抑制できます)。例<br> <code> myMatrix =(LinkedList <IntegerNode> [])new LinkedList <?> [numRows]; </ code>
ネオン

5

構文の問題は別として、行列を表すために配列とリンクリストを使用するのは奇妙に思えます。行列の任意のセルにアクセスできるようにするには、実際の配列または少なくとも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

行ごとにマトリックスをトラバースできるようにする必要がある場合は、行マップタイプをaにすることができTreeMapます。これは、インデックス順に列をトラバースする場合と同じですが、これらのケースが必要ない場合は、HashMapよりも高速ですTreeMap。もちろん、任意のセルを取得および設定し、未設定のnull値を処理するヘルパーメソッドは便利です。


4
class IntegerNodeList extends LinkedList<IntegerNode> {}

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 

LinkedListのジェネリックを見逃しました。
Peter Wippermann、

3

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

この方法でキャストしても機能しますが、厄介な警告が表示されます。

「タイプセーフ:タイプList []の式にはチェックされていない変換が必要です。」

リストの配列の特別なクラスを宣言する:

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

警告を回避するための賢いアイデアです。多分少し良いのはそれのためのインターフェースを使うことです:

public interface IntegerNodeList extends List<IntegerNode> {}

その後

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

警告なしでコンパイルします。

悪くないですよね?


IntegerNodeList:これをどのクラスで使用しますか?たとえば、ArrayList <IntegerNode>を割り当てることはできません。ArrayListも拡張する必要があります...
Hans-PeterStörr'10年

配列の初期化の外でインターフェイスIntegerNodeListを使用する必要はありません。List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; for(int i = 0; i <myMatrix.length; i ++){myMatrix [i] = new ArrayList <IntegerNode>(); }
user306708 2010

1
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];これには微妙ですが重要な問題があります。配列にのみ入れることができIntegerNodeListます。myMatrix[i] = new ArrayList<IntegerNode>();スローされArrayStoreExceptionます。
Radiodef 2015

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

警告はありません。NetBeans 6.9.1、jdk1.6.0_24


1
警告なしですが、OracleのJava SE 6 Update 32を使用すると、「タイプリストはジェネリックではありません。引数<String>でパラメーター化することはできません」というコンパイルエラーが発生します。<String>引数を削除すると、別のエラー「タイプの不一致:LinkedList <String>からリストに変換できません」が生成されます。
マルコラッコビッチ


0

次の操作を行うと、問題のエラーメッセージが表示されます

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

しかし、宣言でリストタイプを削除しただけでは、目的の機能を備えているようです。

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

これら2つの宣言は、私が知らない方法で大幅に異なりますか?

編集する

ああ、今この問題に遭遇したと思います。

行列を繰り返し処理し、forループでリストを初期化することで、うまくいくようです。ただし、他のいくつかのソリューションほど理想的ではありません。

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

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

0

リストの配列が必要です。1つの代替策は、次のことを試してみることです。

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

次にnode_array[i]ArrayList<IntegerNode>またはLinkedList<IntegerNode>(好きなリスト実装の何でも)のヘッド(最初の)ノードを格納します。

この設計では、ランダムアクセスメソッドが失われlist.get(index)ますが、それでもタイプセーフ配列の先頭/最初のノードストアからリストをトラバースできます。

これは、ユースケースによっては許容できる設計の選択になる場合があります。たとえば、私はこのデザインを使用してグラフの隣接リストを表します。ほとんどの使用例では、リスト内のいくつかの頂点にランダムアクセスするのではなく、特定の頂点の隣接リストをたどる必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.