【问题标题】:How to store references to all objects of a class?如何存储对类的所有对象的引用?
【发布时间】:2012-06-11 23:11:42
【问题描述】:

假设有两个类,ObjectA 和 ObjectB。 ObjectA 类有一个创建ObjectB 类对象的方法如下:

private ObjectB createObjectB() {
    Object b = new ObjectB();
    return b;
 }

我想跟踪ObjectB 的所有实例。有什么更好的方法来做到这一点?

  • ArrayList 内部类ObjectA 的形式跟踪所有对象。
  • ObjectB 中的某个类变量。

每种方法的优缺点是什么?如果我知道 ObjectB 对象只会从 ObjectA 中的这种方法创建,这会有所不同吗?

请注意,ObjectA 的实例永远只有一个,但 ObjectB 的实例数量是可变的。

【问题讨论】:

  • 这取决于您为什么需要跟踪对象的所有实例。你的用例是什么?
  • 引用需要用到什么?
  • 为了得到 ObjectB 实例的垃圾收集,最多应该保留weak references 的列表;那里有一些弱 ref 集合类,但不幸的是 JSE 中没有。
  • 我想随时使用 array.length / ArrayList.length 等知道 ClassB 实例的数量。我还希望能够遍历该数组中引用的对象以对每个对象执行某些操作一。如果我有第三类 ObjectC 也可以创建 objectB 对象,并且我只想遍历 objectC 创建的对象,而不是 objectA,最好保留一个单独的数组,还是遍历所有 B 的检查对于一个条件,然后只是修改它们?
  • 我想我会在创建它们的每个类中保存对 B 类对象的引用,然后只在 B 类中保存对这些数组/集合的引用。这样每个对象只需要一个直接引用,同时仍然有一个简单的方法来获取所有现有的 B 对象。只有当一个类第一次请求新的 B 类对象时,才会在 B 类中进行额外的引用,每个后续的 on 只引用一次,因此应该非常有效。谢谢大家!

标签: java instance-variables class-variables


【解决方案1】:

如果您想从代码的不相关部分访问所有创建的对象,您只需要“跟踪”以这种方式创建的对象。否则 1)创建的对象将由变量保存,因此您可以访问它; 2)当没有更多对该对象的引用(因此无法访问)时,垃圾收集器最终会清理内存。

如果您这样做跟踪它们,请记住,当您在集合中拥有对象时,GC 无法释放内存,这可能会导致内存不足错误

【讨论】:

  • 我不会在会话的生命周期内创建 objectB 对象,并希望在会话结束时将它们输出到数据库或其他东西,以便方便保存所有这些都在一个地方。但我也想只遍历由特定类创建的那些,因此保持这种方式也很方便。不确定最初写入两次(并占用双倍内存)是否较慢,或者遍历一个列表以确定哪些需要对它们进行处理?
  • @Ben - 在这种情况下,存储对同一个对象的两个引用可能是最简单的:一个用于数据库,一个在创建它的类中
【解决方案2】:

如果只有一个ObjectA 实例,并且它有一个createB 方法,我会将列表保留在ObjectA 实例 本身上。但实际上我认为这并不重要。

public ObjectB createB(){
   Object B = new ObjectB();
   allBs.add(b); // assuming some sort of List
   return b;
}

我很想知道您为什么要这样做。您可能会遇到线程问题等,具体取决于您的应用及其架构。

【讨论】:

  • 如果 ObjectB 对象可以由多个类创建,并且每个类都想遍历它创建的对象,无论出于何种原因,只保存这些对象的数组会更快。但有时我也想将所有 objectB 对象的记录写入磁盘,因此拥有所有对象的数组会很方便。但是每次创建一个对象时创建两个引用需要比一个更长的时间,而且我不知道检查数组的每个对象中的一个字段(查看哪个类创建它)要慢多少,与仅具有较小的数组开始?
【解决方案3】:

在 ObjectB 中保存一个列表是没有意义的,但是如果您需要对您创建的所有 B 对象的引用,那么在 ObjectA 中的一个列表就会有意义。

【讨论】:

    【解决方案4】:

    这取决于您需要实现的目标。 ObjectB(这是个坏名字,顺便说一句)的实例应该能够相互交谈吗?如果是这样,那么您需要在类中创建一个全局变量(即static 字段),或者您必须将列表保留在ObjectA 中并将其“注入”到ObjectB 的每个实例中 - 这意味着您需要在这两个地方保留参考。

    如果ObjectB 的实例不需要相互通信,通常将列表保留在ObjectA 中就足够了。

    但大多数情况下,根本不需要保留列表。这甚至可能很危险,因为您必须确保列表在耗尽所有内存之前不会增长。

    一般规则是:避免不必要的依赖。通过保留一个列表,您将引入一个具有成本的依赖项(例如,在维护中,您首先需要编写代码)。

    永远警惕你编写的东西的成本 - 很容易让这些廉价的东西积累成真正昂贵的依赖关系,扼杀你。

    【讨论】:

    • 他们不需要互相交谈,但是第三类想不时知道B类的所有实例。我猜如果第三类新创建了所有可能的位置,它可以访问它们的每个列表以获取所有这些位置的组合。与仅在一个地方拥有一大堆所有东西相比,这似乎很混乱。
    • 在某种意义上,AB 实例的工厂。您可以在A(错误)中保留一个列表,或者在创建新实例时发送一个事件。然后A 可以包含对此类事件感兴趣的侦听器列表(C 将注册自己)然后C 可以做任何它想做的事情。这只会引入一个廉价的依赖关系,因为A 不需要知道任何关于C 及其需要的信息。
    【解决方案5】:

    对我来说,对象 A 和对象 C 似乎是管理对象 B 实例的类。

    我有一个类似的场景,我需要跟踪作为基服务类的子类的不同服务(在我的例子中,对象 B 是基类)。

    要创建/启动/停止/重新启动/删除这些服务,我有 2 个管理器类,用于两种不同的目的(如您的情况下的对象 A 和对象 C)。

    在两个管理器类中我都有一个 HashMap

    您可以有一个方法来停止/启动/创建/销毁/删除类 A 或 C 中的 B 对象,该方法采用“名称”ob 对象 B 并在对象 B 上启动相应的操作。

    作为最佳实践,在您的 SessionContextListener 中始终确保调用停止/删除操作以删除此 HashMap 中添加的对象。

    【讨论】:

      【解决方案6】:

      根据您对 ObjectC 的看法,我认为 ObjectA(和 C)维护 ObjectB 的数组是最有意义的。 (实际上,如果您希望添加和减去 B,我建议使用某种集合而不是数组)。

      然后您可以创建一个方法来返回 A 创建的 B 的数量,例如A.countB()

      如果您发现自己需要创建 B 的总数并且您不能使用 A.countB()+C.countB(),那么您有两个选择:B 中的静态地图,其中key 是创建者对象(A、C 或其他),value 是 B 的集合。

      我不鼓励这样做有几个原因,主要是创建的对象会挂起(因此没有 GC,以及潜在的内存问题)。

      另一种方法是使用管理器类来创建和跟踪 B,并在完成实例后非常小心地取消引用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-28
        • 2016-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多