【问题标题】:Two-dimensional array of ListsLists 的二维数组
【发布时间】:2011-10-07 11:58:13
【问题描述】:

我需要一个二维矩阵列表,例如ArrayList,我想知道在这种情况下什么是最可取的。它的大小只需为 4x4。

我应该使用类似的东西

    ArrayList[][] foo = new ArrayList[4][4];

    ArrayList<SomeClass>[][] foo = new ArrayList[4][4];

并在 for 循环中使用适当的类型初始化每个元素或

    ArrayList<ArrayList<ArrayList<SomeClass>>> foo = ArrayList<ArrayList<ArrayList<SomeClass>>>();

第一种方法会生成警告,就像它应该参数化一样,如果我添加使用第二种方法,我会收到未经检查的转换警告。但是,如果我遍历元素并初始化它们,即使我仍然收到警告也不应该有任何问题?最后一种方法不会产生任何警告,可能工作正常,但感觉有点乱。

编辑:我的问题得到了一些不错的答案,即使它有点不清楚。但这基本上是如何制作列表表。创建一个自定义类来处理行/列使它变得容易得多。

【问题讨论】:

  • 第二种方法应该是:ArrayList&lt;SomeClass&gt;[][] foo = new ArrayList&lt;SomeClass&gt;[4][4];,但是有一个列表数组似乎有些尴尬。你真的需要那个二维数组吗?如果是这样,您能否提供更多信息说明原因?
  • 拥有 ArrayList[][] foo = new ArrayList[4][4];会产生错误“无法创建 ArrayList 的通用数组,这就是我忽略它的原因 :)
  • 而我需要它的原因是我有一个包含“结果”的表格。根据操作的结果,我想将这些对象添加到二维数组中的这些列表之一。这会让事情变得更清楚吗? :)

标签: java multidimensional-array arraylist


【解决方案1】:
    public static class Grid<T> {

    public interface TFactory<T> {

        T create();
    }
    private T[] data;
    private int d1;
    private int d2;

    public Grid(int d1,
            int d2,
            Class<T> clazz,
            TFactory<T> fac) {
        this.d1 = d1;
        this.d2 = d2;
        data = (T[]) Array.newInstance(clazz, d1 * d2);
        for (int i = 0; i < data.length; i++) {
            data[i] = fac.create();
        }
    }

    public T get(int c1,
            int c2) {
        return data[c1 * d2 + c2];
    }
}

public static class ArrayListFactory<X> implements Grid.TFactory<ArrayList<X>> {

    public ArrayList<X> create() {
        return new ArrayList();
    }
}

public static void main(String[] args) throws RTXException, ParseException {
    // cannot use new new ArrayList<String>[4][4];, because of generic array creation error
    List<String>[][] a2d = new ArrayList[4][4];
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            a2d[i][j] = new ArrayList<String>();
        }
    }
    Grid g = new Grid(4, 4, ArrayList.class, new ArrayListFactory<String>());
}

这里有两种方法。首先是您要求的,其次是封装版本(将二维数组转换为一维数组以便于内部操作)。

如前所述,您应该尽可能多地将变量声明为接口(但不能更多)。 这意味着,如果您只想说它是一个 List,并且不希望任何人根据具体实现表现出不同的行为,只需使用 List,而不是 ArrayList 作为变量类型。 但是如果你使用例如。 LinkedSet 使用 LinkedSet 作为变量类型(和函数的返回值)可能是个好主意,如果你想“承诺”它会以插入顺序快速列出所有元素。如果你使用 Set,它的用户不应该依赖于任何特定的迭代顺序。

顺便说一句。当心显式初始化。这是很好的语法,但它创建了匿名内部类,并且可能导致有意保留父类。但是,如果您知道自己在做什么并且不可能发生(没有外部参考),那么使用它就没有错。

【讨论】:

    【解决方案2】:

    就像 Alex 已经说过的那样,拥有一个二维列表数组非常复杂,而且很容易出错或以错误的方式使用。

    由于您的数组应该代表一个表,因此您可能希望为行或列创建类,具体取决于更重要的是什么。

    或者,您可以为表格中的每个单元格创建一个类并管理一个二维单元格数组,前提是您确切知道自己拥有多少个单元格:

    class Cell {
      private List<SomeClass> content = new ArrayList<SomeClass>();
      ...
    }
    
    Cell[][] matrix = new Cell[4][4];  //don't forget to initialize each cell
    

    【讨论】:

      【解决方案3】:

      这里是带有显式初始化的 2x2 矩阵的示例。

      List[][] matr = new List[][] { 新列表 { 新 ArrayList(), 新 ArrayList() }, 新列表 { 新 ArrayList(), 新 ArrayList() } }

      【讨论】:

        【解决方案4】:

        修正第一种方法如下:

        List[][] foo = new ArrayList[4][4];

        第二种方法不是你需要的。您正在尝试创建 4 维数组而不是 2 维数组 4*4 元素。

        另外我想给你一个提示:永远不要在作业左侧使用具体类,即ArrayList list = ....使用List list = ...

        并避免使用过于复杂的数据结构。二维列表数组太复杂了。创建封装一些功能的自定义类,然后创建类对象的集合/数组(更好的一维)。

        【讨论】:

        • 好的,谢谢你的提示!你能解释一下为什么你不想在作业的左边使用一个具体的类吗?使用自定义类,我仍然想要类似于 2D 数组的东西。而是将其实现为一维数组并创建一些方法,例如 getRow()getColumn()?
        • @Mattias 在大多数情况下,您希望使用接口而不是具体类,从那时起,如果需要,您可以将ArrayListLinkedList 交换。如果您需要有关功能的更多信息(例如是否排序),您可能需要额外的接口(考虑 SetSortedSet),但了解具体实现对方法的用户几乎没有用处。
        • @AlexR 啊,我明白了。谢谢你的解释!我想我现在已经整理好了,创建了一个自定义类来定义每一列以及一个将结果插入正确位置的方法。它使一切变得容易得多。
        • 嗨,可以用泛型来实现吗?
        猜你喜欢
        • 1970-01-01
        • 2017-01-19
        • 1970-01-01
        • 2019-01-23
        • 2012-02-18
        • 1970-01-01
        • 1970-01-01
        • 2022-01-22
        相关资源
        最近更新 更多