【问题标题】:Dynamic Multidimensional Java Structure to Replace Static Multidimensional Array动态多维 Java 结构替换静态多维数组
【发布时间】:2025-11-27 21:10:01
【问题描述】:

我正在为我的大学重构一小部分开源大型配置管理系统。

我们正在使用一些开源工具进行机器学习,例如 Weka,而我被分配重构的方面是处理数据挖掘和构建规则。

我们一直使用的利物浦和日本的开源文件运行良好,但是当我们在大型项目中使用该程序时会出现一些内存使用问题。

我已经隔离了主要的内存消耗并得出结论,我需要找出不同的数据结构来存储和操作数据。就目前而言,该程序正在使用最终变成非常大的整数、对象、字符串等多维数组。

在我们推导出行为规则后,有几种方法可以简单地重新配置关联的设置。在许多情况下,我们只是添加或减去单个元素,或者只是将多维数组展平。

我主要使用 C/C++ 进行编程,因此我不是 Java 中可用数据结构的专家。我希望用一个动态结构来替换静态数组,该结构可以轻松调整大小,而无需创建第二个多维数组。

现在发生的情况是,每次在多维数组中添加和删除规则、对象或其他杂项数据时,我们都必须创建一个全新的结构。然后我们立即复制到新数组中。

我希望能够简单地使用相同的多维数组并简单地添加新的行和列。随后,我希望能够通过简单地保存一个临时值并覆盖以前的值、左移、右移等来操作结构中的数据。

谁能想到 Java 中任何符合要求的数据结构?

在相关说明中,我研究了显式垃圾收集,但发现我只能通过调用 System.Gc() 或通过调整来操纵 JVM 的垃圾收集行为来真正建议 JVM 收集。有没有更好或更有效的方法?

问候, 编辑器

【问题讨论】:

    标签: java memory-management data-structures


    【解决方案1】:

    如果您的矩阵中有很多空值/零值/假值/空字符串,那么您可以使用sparse matrix 实现来节省空间。 Matrix-toolkits 有几个稀疏矩阵,您可以使用/修改以满足您的需要,或者您可以只使用带有 {x, y} 元组作为键的哈希图。 (hashmap 的另一个优点是有多个可用的外部 hashmap 实现,例如BerkeleyDB,因此您不太可能耗尽内存。)

    【讨论】:

      【解决方案2】:

      要将静态数组替换为动态结构,请使用随数据自动增长的ArrayList。要拥有二维数据结构,请使用 ListList 作为

      List<List<Integer>> dataStore = new ArrayList<List<Integer>>();
      dataStore.add(new ArrayList<Integer>());
      dataStore.add(Arrays.asList(1, 2, 3, 4));
      
      // Access [1][3] as
      System.out.println(dataStore.get(1).get(3)); // prints 4
      

      既然,您谈到了对 垃圾收集 的控制(Java 实际上本身就做得很好),内存管理似乎是最重要的,因为这是导致 re-首先考虑因素。

      您可以查看Flyweight GoF 模式,该模式专注于共享对象而不是重复它们以减少应用程序的内存占用。要启用共享享元对象,需要不可变

      伪代码:

      // adding a new flyweight obj at [2][1]
      fwObjStore.get(2).set(1, FWObjFactory.getInstance(fwKey));
      
      public class FWObjFactory {
          private static Map<String, FWObject> fwMap = new HashMap<String, FWObject>();
      
          public static getInstance(String fwKey) {
              if (!fwMap.containsKey(fwKey)) {
                  fwMap.put(fwKey, newFwFromKey(fwKey));
              }
              return fwMap.get(fwKey);
          }
      
          private static FWObject newFwFromKey(String fwKey) {
              // ...
          }
      }
      

      【讨论】:

      • 我同意,列表列表几乎可以直接替换数组。如果你想聪明一点,将列表封装到一个 Matrix 类中并添加泛型并称自己为快乐。或者只是去寻找已经这样做的数百个实现之一。
      • @BillK 是的,我认为 Apache Commons 有 RealMatrix 实现,而 Google 的 Guava 在同一行有一个通用的 Optional&lt;T&gt;。但是,作为我回答的一部分,我没有任何经验可以详细说明。我可以将它们添加为参考。不重新发明*总是更聪明。
      【解决方案3】:

      我会考虑使用“列表列表”。例如,您可以声明类似

      List<List<Object>> mArray = new ArrayList<List<Object>>();
      

      任何时候你需要添加一个新的“行”,你可以这样做:

      mArray.add (new ArrayList<Object>());
      

      查看List 接口,了解您可以在Java 中使用Lists 做什么,以及哪些类实现了该接口(或您自己的!)。

      【讨论】:

        【解决方案4】:

        Java 中没有多维的东西。Java 有数组。

        你可以使用ArrayList,类型参数为ArrayList

        ArrayList<ArrayList<yourType>> myList = new ArrayList<ArrayList<yourType>>();
        

        另外,不用担心 GC..它会在需要时收集..

        【讨论】:

        • 为什么你会提到 Java SE 6 javadoc 而不是 7?为什么使用 ArrayList 而不是 List 类型的变量? “多维的东西”是..是真的。所以规范也说。然而,该规范始终提到“多维数组”,开发人员社区也是如此。 Java 与其他具有“真正”多维数组的语言之间的一个主要区别是,Java 中的多维数组不需要在每个级别都有相同长度的数组。
        • 当你搜索 Javadocs 时,你会得到 6 个或 7 个(或 5 个)是非常随机的,它们几乎都是相同的,所以这并不重要。
        【解决方案5】:

        为什么不用两个Lists 纠缠在一起呢?像这样:

        List<List<String>> rowColumns = new ArrayList<>();
        
        // Add a row with two entries, or columns:
        List<String> oneRow = Arrays.asList("Hello", "World!");
        rowColumns.add(oneRow);
        

        另外,请考虑使用 Map 并将条目映射到列表。

        垃圾收集通常不需要在 Java 中显式处理。通常,您希望在第一次发生内存泄漏时查找内存泄漏。发生这种情况时,请在缓存中寻找不会死掉的后台线程或强引用。如果你想阅读一些关于后一期的内容,你可以开始herehere

        【讨论】: