java List.contains() 失败而 .equals() 有效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35425609/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
List.contains() fails while .equals() works
提问by idlackage
I have an ArrayList
of Test
objects, which use a string as the equivalency check. I want to be able to use List.contains()
to check whether or not the list contains an object that uses a certain string.
我有一个ArrayList
的Test
对象,使用字符串作为等价检查。我希望能够用来List.contains()
检查列表是否包含使用某个字符串的对象。
Simply:
简单地:
Test a = new Test("a");
a.equals("a"); // True
List<Test> test = new ArrayList<Test>();
test.add(a);
test.contains("a"); // False!
Equals and Hash function:
等号和哈希函数:
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (!(o instanceof Test)) {
return (o instanceof String) && (name.equals(o));
}
Test t = (Test)o;
return name.equals(t.GetName());
}
@Override
public int hashCode() {
return name.hashCode();
}
I read that to make sure contains
works for a custom class, it needs to override equals
. Thus it's super strange to me that while equals
returns true, contains
returns false.
我读到它以确保contains
适用于自定义类,它需要覆盖equals
. 因此,虽然equals
返回真,但contains
返回假对我来说非常奇怪。
How can I make this work?
我怎样才能使这项工作?
回答by Eran
Just because your Test
's equals
may return true when you pass a String to it doesn't mean that String
's equals
will ever return true when you pass a Test
instance to it. In fact, String
's equals
can only return true
when the instance passed to it is another String
:
仅仅因为当您将 String 传递给Test
's 时它equals
可能返回 true 并不意味着当您将一个实例传递给它时String
'sequals
将永远返回 true Test
。事实上,String
'sequals
只能true
在传递给它的实例是另一个时返回String
:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) { // the passed instance must be a String
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
ArrayList
's contains
calls indexOf
which uses the equals
method of the searched instance (the String
"a" in your example), not the element type of the List
(which is Test
in your case) :
ArrayList
的contains
调用indexOf
使用equals
搜索实例的方法(String
在您的示例中为“a”),而不是List
(Test
在您的情况下)的元素类型:
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i])) // o in your case is a String while
// elementData[i] is a Test
// so String's equals returns false
return i;
}
return -1;
}
回答by Andreas
equals()
should always be commutative, i.e. a.equals(b)
and b.equals(a)
should always return the same value. Or symmetric, as the javadoc of equals()
calls it:
equals()
应该始终是可交换的,即a.equals(b)
并且b.equals(a)
应该始终返回相同的值。或symmetric,正如 javadoc 中equals()
所称:
The
equals
method implements an equivalence relation on non-null object references:
- It is reflexive: for any non-null reference value
x
,x.equals(x)
should returntrue
.- It is symmetric: for any non-null reference values
x
andy
,x.equals(y)
should returntrue
if and only ify.equals(x)
returnstrue
.- It is transitive: for any non-null reference values
x
,y
, andz
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
should returntrue
.- It is consistent: for any non-null reference values
x
andy
, multiple invocations ofx.equals(y)
consistently returntrue
or consistently returnfalse
, provided no information used inequals
comparisons on the objects is modified.- For any non-null reference value
x
,x.equals(null)
should returnfalse
.
该
equals
方法在非空对象引用上实现了等价关系:
- 它是自反的:对于任何非空引用值
x
,x.equals(x)
都应该返回true
。- 它是对称的:对于任何非空引用值
x
和y
,x.equals(y)
应该返回true
当且仅当y.equals(x)
回报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
。
Unfortunately, even the Java Runtime Library gets this one wrong. Date.equals(Timestamp)
will compare the millisecond values, ignoring the nanoseconds present in the Timestamp
, while Timestamp.equals(Date)
returns false
.
不幸的是,即使是 Java 运行时库也弄错了这一点。Date.equals(Timestamp)
将比较毫秒值,忽略 中存在的纳秒Timestamp
,而Timestamp.equals(Date)
返回false
。
回答by Michael Burr
The problem is that List<E>.contains(object o)
is documented to return true:
问题是List<E>.contains(object o)
有记录的返回true:
if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
当且仅当此列表包含至少一个元素 e 使得 (o==null ? e==null : o.equals(e))。
(From https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object-)
(来自https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object-)
Note that it doesn't perform the test as e.equals(o)
which is what would be necessary for your test to work. Your equals method fails to work commutatively ('symmetrically' using the terms from the Java docs).
请注意,它不会执行测试,因为e.equals(o)
这是您的测试工作所必需的。您的 equals 方法无法交换地工作(使用 Java 文档中的术语“对称地”)。
Java documents that the equals()
method for a class must follow these rules:
Java 文档说明equals()
类的方法必须遵循以下规则:
The equals method implements an equivalence relation on non-null object references:
- It is reflexive: for any non-null reference value
x
,x.equals(x)
should return true.- It is symmetric: for any non-null reference values
x
andy
,x.equals(y)
should return true if and only ify.equals(x)
returns true.- It is transitive: for any non-null reference values
x
,y
, andz
, ifx.equals(y)
returns true andy.equals(z)
returns true, thenx.equals(z)
should return true.- It is consistent: for any non-null reference values
x
andy
, multiple invocations ofx.equals(y)
consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.- For any non-null reference value
x
,x.equals(null)
should return false.
equals 方法在非空对象引用上实现等价关系:
- 它是自反的:对于任何非空引用值
x
,x.equals(x)
都应该返回 true。- 它是对称的:对于任何非空引用值
x
andy
,x.equals(y)
当且仅当y.equals(x)
返回 true时才应返回 true。- 它是可传递的:对于任何非空引用值
x
,y
, andz
,如果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。
回答by Kunal Surana
If you write
如果你写
test.contains(new Test("a"));
then it will surely return true. You are checking for string object in list of Test.
那么它肯定会返回true。您正在检查测试列表中的字符串对象。