无法在Java中创建LinkedList数组…?


102

我正在研究一个稀疏矩阵类,该类需要使用数组LinkedList来存储矩阵的值。数组的每个元素(即每个LinkedList)代表矩阵的一行。并且,LinkedList数组中的每个元素代表一列和存储的值。

在我的课程中,我将数组声明为:

private LinkedList<IntegerNode>[] myMatrix;

并且,在的构造函数中SparseMatrix,我尝试定义:

myMatrix = new LinkedList<IntegerNode>[numRows];

我最终得到的错误是

无法创建的通用数组LinkedList<IntegerNode>

因此,我对此有两个问题:

  1. 我做错了什么
  2. 如果无法创建数组,为什么在数组的声明中可以接受该类型?

IntegerNode是我创建的课程。而且,我所有的类文件都打包在一起。

Answers:


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 2010年

该实现非常慢。获取[1000] [2000]元素(nodeLists.get(1000).get(2000))将使LinkedList重复3000次!如果有人在索引它,请避免使用LinkedList。ArrayList的索引编制速度更快,但Fredrik的解决方案总体而言更好。
史蒂夫·佐贝尔

142

由于某种原因,您必须转换类型并进行如下声明:

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

我研究了类似的问题,并读到上面的演员表是非常普遍的“ hack”,在整个collections框架中都使用。
卢克

15
IMO,这应该是选择的答案。我还没有尝试过,但是我有一种直觉,觉得Sergey的#2方法会产生很多开销。我对#1表示肯定。列表在几种方式上不如数组有效,在此不做详细介绍,但是我已经做过实验,并且发现与列表相比,使用列表的速度大大降低。只管理自己的数组并重新分配它们,比向列表中添加内容要快。
Ricket


4
我仍然收到“类型安全:未经检查的演员表”警告。鲍勃的解决方案对我来说似乎是最干净的。
Marco Lackovic 2012年

3
在JDK 7中,以上给出了rawtypes警告。可以使用无限制的<?>类型解决此问题,但是您仍然会收到未经检查的警告(可以取消显示)。例如<br> <code> myMatrix =(LinkedList <IntegerNode> [])new LinkedList <?> [numRows]; </ code>
Neon

5

除了语法问题之外,使用数组和链表表示矩阵对我来说似乎很奇怪。为了能够访问矩阵的任意单元,您可能需要一个实际的数组或至少一个a 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 '04

1
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];这有一个微妙但重要的问题。您只能放入IntegerNodeList数组。myMatrix[i] = new ArrayList<IntegerNode>();会抛出ArrayStoreException
Radiodef'Aug

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>转换为List”。
Marco Lackovic 2012年


0

如果我执行以下操作,我会得到有关错误消息的信息

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<>();
}

0

您需要一个List数组,一种替代方法是尝试:

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

然后node_array[i]存储的头(第一个)节点ArrayList<IntegerNode>LinkedList<IntegerNode>(无论您的收藏夹列表实现)。

在这种设计下,您将失去随机访问方法list.get(index),但是您仍然可以遍历列表,从安全类型数组中的头/拳头节点存储开始。

根据您的用例,这可能是可接受的设计选择。例如,我使用这种设计来表示图的邻接列表,在大多数使用情况下,它需要以任何方式遍历给定顶点的邻接列表,而不是随机访问列表中的某些顶点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.