Java ArrayList:当arraylist包含给定对象时,contains()方法返回false

Posted

技术标签:

【中文标题】Java ArrayList:当arraylist包含给定对象时,contains()方法返回false【英文标题】:Java ArrayList: contains() method returns false when arraylist contains the given object 【发布时间】:2012-11-01 21:23:08 【问题描述】:

我遇到了 contains() 方法的问题,即使 ArrayList 包含给定的 Object,它也会返回 false。 我的代码如下:

String [] transaction = dbConnection.getPendingTransaction(username);
if (!onlineConnection.getSentTransactionRequests().contains(transaction)) 
    onlineConnection.getSentTransactionRequests().add(transaction);

    String packet = "RTR" + "_" + transaction[0] + "_" + transaction[2] + 
                        "_" + transaction[3] + "_" + transaction[4];
    onlineConnection.send(packet);

我在两次迭代之间尝试了Thread.sleep(),所以ArrayList 没有成功加载。

【问题讨论】:

equalshashcode 显然不是你的朋友。 拜托,拜托,请将您的交易建模为适当的对象,而不是字符串数组。然后看上面@haylem 的评论。 【参考方案1】:

数组的hashCode()equals() 在涉及到这一点时有点坏(这是一个很长的不同讨论原因)。

一种可能的解决方法是使用ArrayList<ArrayList<String>> 而不是ArrayList<String[]>ArrayListequals() 方法将如您所愿。

例如:

    ArrayList<String> l1 = new ArrayList<>();
    ArrayList<String> l2 = new ArrayList<>();
    l1.add("asdf");
    l2.add("asdf");
    ArrayList<ArrayList<String>> coll = new ArrayList<>();
    coll.add(l1);
    System.out.println(coll.contains(l2));

将产生true,正如预期的那样

【讨论】:

如果这确实是问题所在,那么“长期不同的讨论为什么”将是值得的。 @DonRoby:老实说,我相信在 java 7 中仍然是这种方式的主要原因是向后兼容。我相信,如果设计人员可以在不改变 java 的向后兼容性准则的情况下改变它——他们会……但我不是 Oracle 的架构师,所以我可能是错的。我也认为这是题外话。 确实是这个问题,原因在***.com/questions/8777257/…的相关问题中。【参考方案2】:

查看 getPendingTransaction 和 getSentTransactionRequests 是否应该返回相同的数组而不是创建新的数组。其次,尝试调试并查找数组对象 ID。如果这不一样,但应该是(并且包含相同的元素),请尝试解决此问题(例如创建比较器或列表或类似的东西)。

【讨论】:

【参考方案3】:

问题是数组的equals 被定义为引用相等。换句话说,包含相同元素的两个不同数组不相等...根据equals 方法。

如果您希望“事务”对象的equals 基于字符串的相等性,则需要创建一个自定义类来保存String[],并覆盖equals 方法和@987654326 @方法。


顺便说一句,数组equals(Object) 方法不是“有点坏”。 equals 定义的语义只是反映了任何数组对象本质上都是可变的这一事实。

【讨论】:

【参考方案4】:

这是因为String [] transaction 是对象。当您调用contains 时,列表使用equals 方法将新对象与其他对象进行比较。想象它喜欢做

new Object().equals(new Object())

【讨论】:

不完全正确,请注意,如果集合包含“asdf”并且您检查list.contains(new String("asdf")),您将得到正确的结果。 @amit 谢谢。更新了我的答案。【参考方案5】:

如果你必须使用List&lt;String[]&gt;,可能你使用equals()hashCode()似乎运气不好......

也许你最好创建方法来比较你的对象

类似

public static boolean stringArrayListEquals(List<String[]> list, List<String[]> list2) 
    if (list.size() != list2.size()) return false;
    for (int i = 0; i < list.size(); ++i)
        if (!Arrays.equals(list.get(i), list2.get(i)) return false;
    
    return true;

要测试contains(),您需要另一个循环...

虽然你应该认真地改用List&lt;List&lt;String&gt;&gt;

【讨论】:

【参考方案6】:

我也遇到过类似的问题。我刚刚写了下面的sn-p:

assertContains(list, toLookFor);  // To call the below private method  

private void assertContains(ArrayList<String> list, String toLookFor) 
        String arrayListToString = rulesList.toString();
        
         if (arrayListToString.contains(toLookFor))
                System.out.println("The list contains "+ toLookFor);
            else
                System.out.println("The list does not contains "+ toLookFor);
        
    

【讨论】:

以上是关于Java ArrayList:当arraylist包含给定对象时,contains()方法返回false的主要内容,如果未能解决你的问题,请参考以下文章

java arraylist越界问题

java ArrayList集合

Java的ArrayList

JAVA集合9ArrayList和Vector区别

JAVA-基础-第16章ArrayList集合

Java源码解读系列:ArrayList