List.contains() 失败,而 .equals() 有效
List.contains() fails while .equals() works
我有一个 ArrayList
个 Test
个对象,它们使用字符串作为等价性检查。我希望能够使用 List.contains()
检查列表是否包含使用特定字符串的对象。
简单地说:
Test a = new Test("a");
a.equals("a"); // True
List<Test> test = new ArrayList<Test>();
test.add(a);
test.contains("a"); // False!
等于和哈希函数:
@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();
}
我读到要确保 contains
适用于自定义 class,它需要覆盖 equals
。因此,对我来说超级奇怪的是,虽然 equals
returns 是真的,但 contains
returns 是假的。
我怎样才能完成这项工作?
仅仅因为你的 Test
的 equals
可能 return 在你传递一个字符串给它时为真并不意味着 String
的 equals
将永远 return 当您将 Test
实例传递给它时为真。事实上,String
的 equals
只能 return 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
的 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;
}
问题是 List<E>.contains(object o)
被记录为 return true:
if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
(来自 https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object-)
请注意,它不会像 e.equals(o)
那样执行测试,这是您的测试工作所必需的。您的 equals 方法无法交换地工作('symmetrically' 使用 Java 文档中的术语)。
Java 说明 class 的 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
and y
, x.equals(y)
should return true if and only if y.equals(x)
returns true.
- It is transitive: for any non-null reference values
x
, y
, and z
, if x.equals(y)
returns true and y.equals(z)
returns true, then x.equals(z)
should return true.
- It is consistent: for any non-null reference values
x
and y
, multiple invocations of x.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()
应该总是 commutative, i.e. a.equals(b)
and b.equals(a)
should always return the same value. Or symmetric, as the javadoc of 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
and y
, x.equals(y)
should return true
if and only if y.equals(x)
returns true
.
- It is transitive: for any non-null reference values
x
, y
, and z
, if x.equals(y)
returns true
and y.equals(z)
returns true
, then x.equals(z)
should return true
.
- It is consistent: for any non-null reference values
x
and y
, multiple invocations of x.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
.
不幸的是,即使 Java 运行时库也会出错。 Date.equals(Timestamp)
将比较毫秒值,忽略 Timestamp
中存在的纳秒,而 Timestamp.equals(Date)
returns false
.
如果你写
test.contains(new Test("a"));
那么它肯定return是真的。您正在检查测试列表中的字符串对象。
我有一个 ArrayList
个 Test
个对象,它们使用字符串作为等价性检查。我希望能够使用 List.contains()
检查列表是否包含使用特定字符串的对象。
简单地说:
Test a = new Test("a");
a.equals("a"); // True
List<Test> test = new ArrayList<Test>();
test.add(a);
test.contains("a"); // False!
等于和哈希函数:
@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();
}
我读到要确保 contains
适用于自定义 class,它需要覆盖 equals
。因此,对我来说超级奇怪的是,虽然 equals
returns 是真的,但 contains
returns 是假的。
我怎样才能完成这项工作?
仅仅因为你的 Test
的 equals
可能 return 在你传递一个字符串给它时为真并不意味着 String
的 equals
将永远 return 当您将 Test
实例传递给它时为真。事实上,String
的 equals
只能 return 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
的 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;
}
问题是 List<E>.contains(object o)
被记录为 return true:
if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
(来自 https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object-)
请注意,它不会像 e.equals(o)
那样执行测试,这是您的测试工作所必需的。您的 equals 方法无法交换地工作('symmetrically' 使用 Java 文档中的术语)。
Java 说明 class 的 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()
应该总是 commutative, i.e. a.equals(b)
and b.equals(a)
should always return the same value. Or symmetric, as the javadoc of 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
.
不幸的是,即使 Java 运行时库也会出错。 Date.equals(Timestamp)
将比较毫秒值,忽略 Timestamp
中存在的纳秒,而 Timestamp.equals(Date)
returns false
.
如果你写
test.contains(new Test("a"));
那么它肯定return是真的。您正在检查测试列表中的字符串对象。