【问题标题】:What immutable object works with List.contains?什么不可变对象适用于 List.contains?
【发布时间】:2020-07-08 10:34:44
【问题描述】:

我想创建一个坐标列表并能够检查该列表是否包含新坐标。

我已经尝试实现Pair,但是使用List.contains()Pair 不起作用,总是返回false。

我可以使用哪些其他对象来检查List.contains()

【问题讨论】:

  • List.contains 迭代列表项,查找使用equals(Object) 匹配的元素。您可以使用任何正确实现equals(Object) 的类(它也应该有hashCode() 的相应实现,尽管List.contains 没有使用它)。请出示您的Pair 班级。
  • Pair 本身仍然需要实现 equals 和 hashcode btw。请显示重现问题的代码。配对课程对我来说似乎毫无价值,我会用 x 和 y 字段制作一个坐标类,或者如果我不想制作自己的课程,则使用 2 元素数组。
  • 你能添加对List.contains失败的代码吗?
  • 你必须实现 hashcode & equals 才能可靠地工作。
  • 还可以考虑使用HashSet

标签: java list immutability contains


【解决方案1】:

这可能是因为您的Pair 实现没有提供覆盖的equals 方法。我能够使用以下代码重现您的问题:

//a plain POJO, in Pair.java
public class Pair<A, B> {
    private A a;
    private B b;

    public Pair(A a, B b) {
        this.a = a;
        this.b = b;
    }

    public A getA() {
        return a;
    }

    public B getB() {
        return b;
    }
}

//... Main.java

public class Main {
    public static void main(String[] args) {
        List<Pair<Integer, String>> list = new ArrayList<>();
        Pair<Integer, String> one = new Pair<>(1, "hello");
        Pair<Integer, String> two = new Pair<>(1, "hello");
        list.add(one);
        System.out.println(list.contains(two));
    }
}

这会打印出false,因为List.contains 使用对象相等性作为测试(Object 类中的默认equals 方法)。例如,对于上面的代码,one.equals(two) 的计算结果为 false,因为它们不是同一个对象。要解决此问题,您必须提供一个 equals 方法来查看每个字段并单独比较它们:

//in class Pair
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Pair<?, ?> pair = (Pair<?, ?>) o;
    return Objects.equals(a, pair.a) &&
            Objects.equals(b, pair.b);
}

您可以将编写此代码的繁琐且容易出错的任务委托给您的 IDE。我正在使用 Intellij,只需单击 Code/Generate/equals() and hashcode() 即可。对于这种特殊情况,您不需要hashcode(),但将equals()hashcode() 放在一起总是一个好主意。现在,当List.contains 尝试查找与您提供的元素相同的元素时,它将使用这种新的更合适的方法。如果您再次运行 main 方法,您会看到它的计算结果为 true

【讨论】:

  • 感谢您提供与 Pair 相关的解决方案,但为了简单起见,我更感兴趣的是找到一些与 List.contains() “开箱即用”本身一起使用的数据结构。
  • @Recessive 如果“数据结构”是指“类”,那么只要它们正确覆盖Object.equals(),所有这些都可以使用List.contains。例如,尝试使用 IntegerDate
  • @Recessive 对于具有“开箱即用”的equals 方法的类,如果它是您自己创建的类,那么您必须指定正确实现的equals() 方法。如果“开箱即用”是指标准库类,那么您可以查看 Java 使用的类,其中很多都覆盖了 equals() 方法。参见例如the Integer class
【解决方案2】:

List.contains 使用Object.equals 方法检查两个对象是否相等。因此,它仅适用于实现了Object.equals 方法的对象。如果您正在编写自己的 Pair 类,请确保给它一个 equals 方法。

【讨论】:

    【解决方案3】:

    我认为您的 Pair 包含相同的值,但对象不一样。那是因为它不起作用。您可以改用地图。

    如何使用地图:

    Map<String, Integer> map = new HashMap<>();
    map.put("Hello", 0); // add key an value to map (Key: "Hello", Value: 0)
    map.put("World", 1); // add key an value to map (Key: "World", Value: 1)
    
    if (map.containsKey("World")) { // check if map contains key: "World"
      System.out.println(map.get("World")); // try return value by key: returns 1
      System.out.println(map.get("world")); // try return value by key: returns null
    }
    
    if (map.containsKey("Hello")) { // check if map contains key: "Hello"
      System.out.println(map.get("Hello")); // try return value by key: returns 0
      System.out.println(map.get("hello")); // try return value by key: returns null
    }
    

    【讨论】:

    • 当我使用pairs时,我将我的列表定义为List&lt;Pair&lt;Integer, Integer&gt;&gt; checked = new ArrayList&lt;&gt;();。即使列表清楚地包含Pair (3,4),当我执行checked.contains(new Pair(3,4)); 时,这仍然失败。
    • 这并不能真正回答问题 + Others aren't recommended 为什么?
    • 这个答案并不是很有帮助......也许解释一下如何使用地图?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多