使用Java ArrayList评估包含字符串的对象包含()

时间:2013-10-18 13:41:52

标签: java arraylist

我想对对象进行更深入的字符串检查,以便能够执行以下操作:

List<MyObj> myList = new ArrayList<MyObj>() {{
    add(new MyObj("hello"));
    add(new MyObj("world"));
}};

System.out.println(myList.contains("hello")); // true
System.out.println(myList.contains("foo")); // false
System.out.println(myList.contains("world")); // true

但是使用以下完整代码

会对每个人产生错误
/* Name of the class has to be "Main" only if the class is public. */
class Ideone {
    public static class MyObj {
        private String str;
        private int hashCode;

        public MyObj(String str) {
            this.str = str;
        }

        public @Override boolean equals(Object obj) {
            System.out.println("MyObj.equals(Object)");
            if (obj == this) {
                return true;
            }

            if (obj instanceof String) {
                String strObj = (String) obj;
                return strObj.equals(str);
            }

            return false;
        }

        public @Override int hashCode() {
            if (hashCode == 0) {
                hashCode = 7;
                for (int i = 0; i < str.length(); ++i) {
                    hashCode = hashCode * 31 + str.charAt(i);
                }
            }

            return hashCode;
        }
    }

    public static final MyObj obj1 = new MyObj("hello");
    public static final MyObj obj2 = new MyObj("world");
    public static void main (String[] args) throws java.lang.Exception {
        List<MyObj> myList = new ArrayList<MyObj>() {{
            add(obj1);
            add(obj2);
        }};

        System.out.println(myList.contains("hello"));
        System.out.println(myList.contains("foo"));
        System.out.println(myList.contains("world"));
    }
}

如果我是对的,列表对象应该使用equals()hashCode()来评估包含的对象。 所以我@Override他们并另外检查他们的字符串。 但它永远不会进入equals(),因为没有输出MyObj.equals(Object)

6 个答案:

答案 0 :(得分:7)

java.util.ArrayList#indexOf在ArrayList内部用于contains()

有支票,

o.equals(elementData[i])

因此,字符串与您的对象进行比较,因此调用String.equals()来检查相等性。

答案 1 :(得分:5)

您根本没有履行equals合同:

equals方法在非null对象引用上实现等价关系:

  • 它是自反的:对于任何非空引用值x,x.equals(x)应该返回true。 你的不是反身
  • 它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。 你的不对称。
  • 它是传递性的:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true 。 您的不可传递
  • 它是一致的:对于任何非空引用值x和y,x.equals(y)的多次调用始终返回true或始终返回false,前提是没有修改在对象上的equals比较中使用的信息。
  • 对于任何非空引用值x,x.equals(null)应返回false。

因此,如果不遵守方法的合同,就不能指望预期的行为。

就是说,例如,什么保证你将在ArrayList中包含的对象上调用equals,而不是以其他方式调用,例如"hello".equals(new MyObj("hello"))。你不能保证它,但因为equals通常应该是对称的而不是你不应该介意的。

答案 2 :(得分:1)

正如其他人所指出的那样,问题是你的 equals方法永远不会被调用。当您调用myList.contains("hello")时,ArrayList会检查"hello".equals(<MyObj>),而不是相反。

相反,我建议您正确实施equals方法 ,以便将两个MyObject个等同value的实例视为相等,然后创建一个帮助方法像这样:

public boolean myContains(List<MyObj> list, String value) {
    return list.contains(new MyObj(value));
}

答案 3 :(得分:0)

List<MyObj> myList = new ArrayList<MyObj>()

MyObj的列表,因此您需要在检查MyObj时使用myList.contains

System.out.println(myList.contains(new MyObj("hello")));
System.out.println(myList.contains(new MyObj("foo")));
System.out.println(myList.contains(new MyObj("world")));

答案 4 :(得分:0)

您要求列表将StringMyObj进行比较......它们永远不会“相等”。请改为使用地图:

Map<String, MyObj> map = new HashMap<String, MyObj>() {{
    put("hello", new MyObj("hello"));
    put("world", new MyObj("world"));
}};

然后你可以使用:

if (map.containsKey("hello"))

并获取相应的对象:

MyObj o = map.get("hello"); // get() returns null if key not found

答案 5 :(得分:0)

当包含执行时,调用的对象不等于String类中的对象。 和String实现检查instanceof是否该类是一个String来执行类似String的操作来确定答案。如果object不是String,则返回false;