4

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

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)

4

6 回答 6

7

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

有一张支票,

o.equals(elementData[i])

所以有字符串与你的对象的比较,所以String.equals()被调用来检查相等性。

于 2013-10-18T13:46:14.467 回答
5

您根本没有履行equals合同:

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

  • 它是自反的:对于任何非空引用值 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。

因此,如果不尊重该方法的合同,您就无法期待预期的行为。

举个例子,什么可以保证你 equals 将被包含在 ArrayList 中的对象上调用,而不是以其他方式调用,例如"hello".equals(new MyObj("hello")). 您对此没有任何保证,但因为equals通常应该是对称的,而不是您不应该介意的。

于 2013-10-18T13:46:03.333 回答
1

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

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

public boolean myContains(List<MyObj> list, String value) {
    return list.contains(new MyObj(value));
}
于 2013-10-18T13:57:15.630 回答
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")));
于 2013-10-18T13:48:11.443 回答
0

您要求列表将 aString与 a进行比较MyObj……它们永远不会“相等”。请尝试使用地图:

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
于 2013-10-18T13:52:38.817 回答
0

它不等于包含执行时调用的对象,而是来自 String 类的对象。而String实现用instanceof检查类是否是String来执行类似String的操作来判断答案。如果对象不是字符串,它将返回 false;

于 2013-10-18T15:27:18.430 回答