ArrayList 的 contains() 方法对于自定义对象总是 returns false
ArrayList's contains() method always returns false with custom object
我在继续我的代码时遇到了一些麻烦,我会给你一个简单的例子(虽然它会更复杂一些,但这个简单的代码也不能正常工作)。
class Sign {
private String char;
private Integer freq;
public Sign(String c) {
this.char = c;
}
@Override
public boolean equals(Object o) {
String check = (String)o;
return check.equals(this.char);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + this.char.hashCode();
return hash;
}
}
为了简单起见,我假设在 equals 方法中总是会有一个字符串。还有一些 hashCode() 也可以确保 contains() 方法可以工作,这里是测试本身:
ArrayList<Sign> queueOfSigns = new ArrayList<>();
Sign test = new Sign("C");
String c = "C";
queueOfSigns.add(test);
if(queueOfSigns.contains("C"))
System.out.println("I am here!");
无论如何,在这种情况下,这个简单的测试代码总是 returns false - 所以 "I'm here" 消息永远不会出现。我一直在尝试一些不同的方法来处理我的代码,但这是因为这样做的想法是从字符串文本中获取单个字符并检查单个字符是否已经存在于 ArrayList 中。尽管如此 - 如果这个简单的测试无法正常工作,我无法继续,所以我想问你 - 我错过了什么。这是我第一次真正使用 equals() 和 hashCode() 方法让我自己的对象与 contains() 方法一起正常工作。
您的 equals
实施不正确。 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
.
无法将您的 Sign
class equals
实例化为字符串。
您的 equals
方法实施不正确。违反了Object.equals
:
的总契约
- 它不是自反的 - 因为当参数不是字符串时它会抛出异常,
x.equals(x)
其中 x
是 Sign
将因异常而崩溃。
- 它不是对称的 -
x.equals(y)
与 y.equals(x)
的值不同 return,如果 y
是一个字符串并且 x
是一个 Sign
- 它不一致 - 因为当参数不是字符串时它可能会抛出异常,而不仅仅是 return true 或 false。
在较低的抽象层次上,这个问题的原因是 contains
的实现。根据文档:
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
ArrayList
实际上调用了o.equals(e)
,o
是你传入的字符串。所以它实际上调用了String
中的equals
方法。
如果contains
调用了e.equals(o)
,那么你的程序会打印"I'm here",但是你的equals
仍然违反约定。
更好的equals
实现是这样的:
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o.getClass() == this.getClass()) {
Sign other = (Sign)o;
return other.$char.equals($char); // I have renamed 'char' to '$char' since the former is not a valid identifier
} else {
return false;
}
}
您的客户端代码:
ArrayList<Sign> queueOfSigns = new ArrayList<>();
Sign test = new Sign("C");
Sign c = new Sign("C");
queueOfSigns.add(test);
if(queueOfSigns.contains(c))
System.out.println("I am here!");
编辑:
我想这就是您要找的:
arrayList.stream()
.filter(x -> x.getChar().equals("C"))
.findFirst().isPresent() // this returns true if a sign with C is found in the array list
我在继续我的代码时遇到了一些麻烦,我会给你一个简单的例子(虽然它会更复杂一些,但这个简单的代码也不能正常工作)。
class Sign {
private String char;
private Integer freq;
public Sign(String c) {
this.char = c;
}
@Override
public boolean equals(Object o) {
String check = (String)o;
return check.equals(this.char);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + this.char.hashCode();
return hash;
}
}
为了简单起见,我假设在 equals 方法中总是会有一个字符串。还有一些 hashCode() 也可以确保 contains() 方法可以工作,这里是测试本身:
ArrayList<Sign> queueOfSigns = new ArrayList<>();
Sign test = new Sign("C");
String c = "C";
queueOfSigns.add(test);
if(queueOfSigns.contains("C"))
System.out.println("I am here!");
无论如何,在这种情况下,这个简单的测试代码总是 returns false - 所以 "I'm here" 消息永远不会出现。我一直在尝试一些不同的方法来处理我的代码,但这是因为这样做的想法是从字符串文本中获取单个字符并检查单个字符是否已经存在于 ArrayList 中。尽管如此 - 如果这个简单的测试无法正常工作,我无法继续,所以我想问你 - 我错过了什么。这是我第一次真正使用 equals() 和 hashCode() 方法让我自己的对象与 contains() 方法一起正常工作。
您的 equals
实施不正确。 equals
有特定的合同;该代码试图违反该合同。来自文档:
The equals method implements an equivalence relation on non-null object references:
- It is reflexive: for any non-
null
reference valuex
,x.equals(x)
should returntrue
.- It is symmetric: for any non-
null
reference valuesx
andy
,x.equals(y)
should returntrue
if and only ify.equals(x)
returnstrue
.- It is transitive: for any non-
null
reference valuesx
,y
, andz
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
should returntrue
.- It is consistent: for any non-
null
reference valuesx
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 valuex
,x.equals(null)
should returnfalse
.
无法将您的 Sign
class equals
实例化为字符串。
您的 equals
方法实施不正确。违反了Object.equals
:
- 它不是自反的 - 因为当参数不是字符串时它会抛出异常,
x.equals(x)
其中x
是Sign
将因异常而崩溃。 - 它不是对称的 -
x.equals(y)
与y.equals(x)
的值不同 return,如果y
是一个字符串并且x
是一个Sign
- 它不一致 - 因为当参数不是字符串时它可能会抛出异常,而不仅仅是 return true 或 false。
在较低的抽象层次上,这个问题的原因是 contains
的实现。根据文档:
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
ArrayList
实际上调用了o.equals(e)
,o
是你传入的字符串。所以它实际上调用了String
中的equals
方法。
如果contains
调用了e.equals(o)
,那么你的程序会打印"I'm here",但是你的equals
仍然违反约定。
更好的equals
实现是这样的:
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o.getClass() == this.getClass()) {
Sign other = (Sign)o;
return other.$char.equals($char); // I have renamed 'char' to '$char' since the former is not a valid identifier
} else {
return false;
}
}
您的客户端代码:
ArrayList<Sign> queueOfSigns = new ArrayList<>();
Sign test = new Sign("C");
Sign c = new Sign("C");
queueOfSigns.add(test);
if(queueOfSigns.contains(c))
System.out.println("I am here!");
编辑:
我想这就是您要找的:
arrayList.stream()
.filter(x -> x.getChar().equals("C"))
.findFirst().isPresent() // this returns true if a sign with C is found in the array list