【问题标题】:Why doesn't java.util.HashSet have a get(Object o) method?为什么 java.util.HashSet 没有 get(Object o) 方法?
【发布时间】:2012-12-01 13:24:48
【问题描述】:

我已经看到其他关于根据索引值从Set 获取对象的问题,我理解为什么这是不可能的。但是我无法找到一个很好的解释来解释为什么不允许通过对象获取,所以我想我会问。

HashSetHashMap 支持,因此从中获取对象应该非常简单。就像现在一样,看来我必须遍历 HashSet 中的每个项目并测试似乎没有必要的相等性。

我可以只使用Map,但我不需要键:值对,我只需要Set

例如说我有Foo.java:

package example;

import java.io.Serializable;

public class Foo implements Serializable {

    String _id;
    String _description;

    public Foo(String id){
        this._id = id
    }

    public void setDescription(String description){
        this._description = description;
    }

    public String getDescription(){
        return this._description;
    }

    public boolean equals(Object obj) {
        //equals code, checks if id's are equal
    }

    public int hashCode() {
        //hash code calculation
    }

}

Example.java:

package example;

import java.util.HashSet;

public class Example {

    public static void main(String[] args){
        HashSet<Foo> set = new HashSet<Foo>();

        Foo foo1 = new Foo("1");
        foo1.setDescription("Number 1");

        set.add(foo1);
        set.add(new Foo("2"));

        //I want to get the object stored in the Set, so I construct a object that is 'equal' to the one I want.
        Foo theFoo = set.get(new Foo("1")); //Is there a reason this is not allowed?
        System.out.println(theFoo.getDescription); //Should print Number 1
    }

}

是否因为 equals 方法旨在测试“绝对”相等而不是“逻辑”相等(在这种情况下contains(Object o) 就足够了)?

【问题讨论】:

  • 如果你想要索引,你有列表。 HashSet 不能保证插入顺序,所以 get 方法没有意义。您缺少的是实现 equals 并使用 contains() 它将迭代并找到对象。
  • @assylias 这与我所询问的情况非常接近。但是,我不喜欢包含第三方库的答案。
  • 在 HashSet 中它几乎就在那里...set.contains 代表map.contains,它确实:return getEntry(key) != null; 其中getEntry(key).getKey(); 是您要寻找的...不知道为什么会这样不包括在内...
  • 诚然,HashMap 也没有提供这样的方法……

标签: java hashset


【解决方案1】:

Set 是一个 Collection 对象,将 a.equals(b) == true 视为重复对象,因此尝试获取您已有的相同对象是没有意义的。

如果您尝试从集合中get(Object)Map 可能更合适。

你应该写的是

Map<String, String> map = new LinkedHashMap<>();

map.put("1", "Number 1");
map.put("2", null);
String description = map.get("1");

如果一个对象不在集合中(基于equals),添加它,如果它在集合中(基于equals)给我该对象的集合实例

万一你需要这个,你可以使用Map

Map<Bar, Bar> map = // LinkedHashMap or ConcurrentHashMap

Bar bar1 = new Bar(1);
map.put(bar1, bar1);

Bar bar1a = map.get(new Bar(1));

【讨论】:

  • 我明白为什么有人会想要这样的东西:如果一个对象不在集合中(基于等于),添加它,如果它在集合中(基于等于)给我集合的该对象的实例。
  • 有点...除了它实际上可能有用,如果你有效地规范化。你不会得到 same 对象 - 你会得到一个 equal 对象。
  • 我试图在示例中展示的是对象具有标识符(控制它与其他 Foo 类型的相等性)以及任何数量的其他字段对其没有贡献的想法身份。我希望能够通过构造一个“相等”Foo 对象从 Set(包括额外的字段)中获取对象。
  • Set 的全部意义在于equal 元素是可以互换的。听起来你想要的是Map&lt;Foo, Foo&gt;
  • @FGreg 甚至 Map&lt;String, Foo&gt; 因为键实际上是一个字符串。您不应将用于查找的内容与您查找的内容混淆。
【解决方案2】:

你的最后一句话就是答案。

get(Object o) 将通过HashSet 寻找另一个等于o 的对象(使用equals(o) 方法)。所以确实和contains(o)一样,只是返回的结果不一样。

【讨论】:

    【解决方案3】:

    如果您想知道new Foo("1"); 对象已经存在于set 中,那么您需要使用contains 方法:

    boolean present =  set.contains(new Foo("1"));
    

    不支持get 类型的方法,即set.get(new Foo("1"));,因为它没有意义。您已经拥有该对象,即new Foo("1"),那么您将通过get 方法查看哪些额外信息。

    【讨论】:

    • 您已经拥有对象,即 new Foo("1") => 不完全是 - 他有另一个实例,它恰好是相等的,但它仍然是一个不同的对象.
    • @assylias 我的意思是:在调用 get 之前,会创建 new Foo("1") 实例。无论您写喜欢Foo one = new Foo("1");set.get(one); 还是set.get(new Foo("1"));,您都会首先创建new Foo("1")。现在,当您拥有new Foo("1") 时,除了知道其存在之外还需要什么?
    • Set 中原始Foo 对象上的额外字段是我所追求的。创建new Foo("1")等于Set中的对象,但不包含Set中对象所包含的额外信息。
    • @FGreg:我现在得到了你的要求。在这种情况下,我认为您需要迭代集合或对键和完整对象使用 HashMap。这似乎不是常见的要求,因此没有直接支持。
    【解决方案4】:

    HashSet 比 HashMap 简单一点。如果你不需要 HashMap 的特性,为什么要使用它?如果像 getObject(ObjectType o) 这样的方法是由 Java 实现的,我们不需要在调用 contains() 方法后遍历集合...

    【讨论】:

      【解决方案5】:

      Java 地图/集合备忘单

      它会包含键/值对还是仅包含值?

      1) 如果它包含pairs,则选择一个映射。顺序重要吗?

      。 1-1) 如果,按照插入顺序还是按键排序?

      。 . 1-1-1) 如果已订购,LinkedHashMap

      。 . 1-1-2) 如果已排序,TreeMap

      。 1-2) 如果顺序很重要,HashMap

      2) 如果它只存储 values,则选择是一个集合。它会包含重复项吗?

      。 2-1) 如果ArrayList

      。 2-2) 如果 not 包含重复项,则主要任务是搜索元素 (包含/删除)?

      。 . 2-2-1) 如果 noArrayList

      。 . 2-2-2) 如果,顺序重要吗?

      。 . . 2-2-2-1) 如果顺序重要,HashSet

      。 . . 2-2-2-2) 如果,按照插入顺序还是按值排序?

      。 . . . 2-2-2-2-1) 如果有序LinkedHashSet

      。 . . . 2-2-2-2-2) 如果排序TreeSet

      【讨论】:

      【解决方案6】:

      正如大家之前提到的,没有这样的方法是有充分理由的。话虽如此,如果您希望使用单线(几乎)从 java 8 中的 HashSet 获取某个对象,只需使用流。在你的情况下,它会是这样的:

      Foo existing = set.stream().filter(o -> o.equals(new Foo("1"))).collect(Collectors.toList()).iterator().next();
      

      请注意,如果元素不存在,则会引发异常,因此它在技术上不是单行的,但如果过滤器被正确实施,它应该比对集合元素的传统迭代更快。

      【讨论】:

        【解决方案7】:

        没有get的原因很简单:

        如果您需要从集合中获取对象 X 是因为您需要 X 中的某些东西而您没有该对象。

        如果您没有该对象,那么您需要一些方法(密钥)来定位它。 ..它的名字,一个数字什么的。这就是地图的意义所在。

        map.get("key") -> X!

        集合没有键,你需要遍历它们来获取对象。

        那么,为什么不添加一个方便的 get(X) -> X

        这没有任何意义,因为你已经有了 X,纯粹主义者会说。

        但现在把它当作非纯粹主义者,看看你是否真的想要这个:

        假设我创建了对象 Y,它与 X 的等号匹配,因此 set.get(Y)->X。 Volia,那么我可以访问我没有的 X 的数据。比如说 X 有一个名为 get flag() 的方法,我想要它的结果。

        现在看看这段代码。

        是的

        X = map.get(Y);

        所以 Y.equals(x) 为真!

        但是..

        Y.flag() == X.flag() = 假。 (他们不是平等的吗?)

        所以,你看,如果 set 允许你得到这样的对象,那肯定是破坏了 equals 的基本语义。稍后您将与 X 的小克隆一起生活,他们都声称它们是相同的,但实际上它们不是。

        您需要一张地图,用于存储内容并使用密钥检索它。

        【讨论】:

          【解决方案8】:

          Set 上的 get 方法的一个常见用例可能是实现一个实习生集。如果这是您想要实现的目标,请考虑使用 Google Guava 的 Interner 接口和 Interners 工厂。

          【讨论】:

            【解决方案9】:

            如果你只想知道Hashset里面有什么,你可以使用.toString();方法来显示所有Hashset的内容,用逗号隔开。

            【讨论】:

              【解决方案10】:

              我遇到了与主题作者相同的问题,我有一个真正的原因 一个 Set 应该有一个 get 方法: 我覆盖了equals of e.g. X,集合 Set 的内容等包含 对象不一定与选中的对象相同。在我的场景中,我将删除 语义在另一个集合中翻倍,并通过一些关系丰富“原始” 的“双”,所以我需要“原始”才能删除双。

              【讨论】:

                【解决方案11】:

                get(Object o) 当我们将一个信息链接到其他信息时很有用,就像在 HashMap 中找到的键值对一样。因此,对一个信息使用 get() 方法,我们可以获得第二个信息,反之亦然.

                现在,如果 HashSet 提供 get(Object o) 方法,您需要传递一个对象。因此,如果您有对象要传递给 get(Object o) 方法,这意味着您已经拥有该对象,那么 get(Object o) 方法需要什么。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-10-18
                  • 2014-09-26
                  • 2022-01-02
                  • 2013-02-02
                  • 1970-01-01
                  • 2019-11-23
                  • 2020-09-23
                  相关资源
                  最近更新 更多