【问题标题】:What would be a good way to implement a set collection with weak references, compares by reference, and is also sortable in Java?用弱引用实现集合集合、按引用进行比较以及在 Java 中也可排序的好方法是什么?
【发布时间】:2011-08-14 21:33:22
【问题描述】:

我想要一个允许特定类型的其他对象注册自己的对象。理想情况下,它将对它们的引用存储在某种集合中,并让 .equals() 通过引用而不是值进行比较。它不应该一直保持排序,但它应该能够在集合被迭代之前进行排序。

浏览 Java 集合库,我看到了我在不同集合类型上寻找的各种功能,但我不确定应该如何使用它们来构建我正在寻找的集合类型为。

如果这很重要的话,这就是 Android 环境中的 Java。

【问题讨论】:

  • “对同一对象的单独引用”是什么意思?
  • Afaik 对同一对象的单独引用仅在非常有限的情况下在 Java 中是可能的,例如当涉及序列化时。在谈论“相同对象”时,您真的是指这种情况还是您的意思是“相等”对象?在前者的情况下,您不能依靠比较引用来测试对象身份,我想只有在对象带有唯一标识符时才能确定这一点。
  • 对不起,我的意思是类似 IdentityHashMap,使用引用相等而不是对象相等。也就是说, .equals() 只是做 ==

标签: java android data-structures collections dalvik


【解决方案1】:

Java 内置的基于树的集合不起作用。

为了说明,考虑一个包含对节点“B”、“C”和“D”的弱引用的树:

   C
B     D

现在让弱引用'C'被收集,留下null:

   -
B     D

现在向树中插入一个元素。 TreeMap/TreeSet 没有足够的信息来选择左子树或右子树。如果您的比较器说 null 是一个小值,那么在插入“A”时它将是不正确的。如果它说null是一个很大的值,插入'E'时会不正确。

按需排序是一个不错的选择。

更强大的解决方案是使用ArrayList<WeakReference<T>> 并实现一个Comparator<WeakReference<T>>,该Comparator<WeakReference<T>> 委托给Comparator<T>。然后在迭代之前调用Collections.sort()

Android 的 Collections.sort 在幕后使用 TimSort,因此如果输入已经部分排序,它会非常高效地运行。

【讨论】:

  • 原问题没有指定弱引用。
  • 我可以在包含类中使用 IdentityHashMap 以避免 .contains() 的开销吗?当一个对象注册到该类时,它可以把它放在 ArrayList 和 IdentityHashMap 中。在将对象添加到 ArrayList 之前进行的重复检查可以只检查对该对象的引用是否作为键存在于哈希映射中。
  • @Jared 在帖子的标题中。
  • @VWD2 可以的。或者将重复项放入 ArrayList 并在迭代时将其清空?
【解决方案2】:

也许集合类的抽象级别低于您正在寻找的抽象级别?听起来您想要的最终产品是一个能够以用户定义的排序顺序进行迭代的缓存。如果是这样,也许 Google Guava 库中的缓存接口已经足够接近你想要的了:

http://code.google.com/p/guava-libraries/source/browse/trunk/guava/src/com/google/common/cache/Cache.java

乍一看,该包中的 CacheBuilder 似乎不允许您使用用户定义的迭代顺序构建实现。但是,它确实提供了一个可能足以满足您需求的地图视图:

List<Thing> cachedThings = Lists.newArrayList(cache.asMap().values());
Collections.sort(cachedThings, YOUR_THING_COMPARATOR);
for (Thing thing : cachedThings) { ... }

即使这不是您想要的,该包中的类也可能会为您提供一些有用的见解:将引用与集合一起使用。

【讨论】:

    【解决方案3】:

    免责声明:这是一条评论,但有点大,如果它不能解决您的问题,请见谅:

    Java 中的引用

    只是为了澄清我所说的引用是什么意思,因为它实际上并不是 Java 中常用的一个术语:Java 并不真正使用引用或指针。它使用一种可以(并且默认情况下)分配给特殊null 实例的伪引用。无论如何,这是解释它的一种方式。在 Java 中,这些伪引用是处理 Object 的唯一方法。当我说引用时,我指的是这些伪引用。

    套装

    任何Set 实现都不允许在其中包含对同一对象的两个引用,因为它使用身份相等来进行此检查。这违反了集合的数学概念。 Java Sets 忽略任何添加重复引用的尝试。

    不过,您在评论中提到了Map...您能澄清一下您所追求的收藏类型吗?为什么你需要在其中进行这种平等检查?你在用 C++ 术语思考吗?我会尝试编辑我的答案以便更有帮助:)

    编辑:我认为这可能是你的目标;)所以TreeSet 应该可以解决问题!在出现性能问题之前,我不会担心性能。简单性对于可读性、维护和防止错误非常有用。如果性能确实成为问题,理想情况下您应该分析您的代码并只优化证明存在问题的区域。

    【讨论】:

    • 只要一个集合在您尝试向其中添加元素时使用身份相等性进行检查,这就是我的意思。我想在这种情况下我可以使用排序集,但我并不真正需要始终维护订单的开销。它只需要能够在特定时间进行排序和迭代。
    • 我的计划是让包含类有一个像'isSorted'这样的属性,它最初设置为true,但每次添加到集合时都设置为false。这样,当我需要以特定顺序迭代集合时,它可以事先检查属性以查看是否需要在迭代之前重新排序集合。我会更频繁地对集合进行迭代,而不是在其中添加或删除元素。
    • 我假设 TreeSet 不使用弱引用?
    • 不,Java 中没有这样的东西。
    猜你喜欢
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 2013-11-13
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多