Java ArrayList未使用重写的equals
我在获取ArrayList以正确使用重写的equals时遇到问题。问题是,我试图对单个键字段使用equals to only测试,并使用ArrayList.contains()测试是否存在具有正确字段的对象。这里有一个例子Java ArrayList未使用重写的equals,java,arraylist,overriding,equals,Java,Arraylist,Overriding,Equals,我在获取ArrayList以正确使用重写的equals时遇到问题。问题是,我试图对单个键字段使用equals to only测试,并使用ArrayList.contains()测试是否存在具有正确字段的对象。这里有一个例子 public class TestClass { private static class InnerClass{ private final String testKey; //data and such InnerClass(S
public class TestClass {
private static class InnerClass{
private final String testKey;
//data and such
InnerClass(String testKey, int dataStuff) {
this.testKey =testKey;
//etc
}
@Override
public boolean equals (Object in) {
System.out.println("reached here");
if(in == null) {
return false;
}else if( in instanceof String) {
String inString = (String) in;
return testKey == null ? false : testKey.equals(inString);
}else {
return false;
}
}
}
public static void main(String[] args) {
ArrayList<InnerClass> objectList = new ArrayList<InnerClass>();
//add some entries
objectList.add(new InnerClass("UNIQUE ID1", 42));
System.out.println( objectList.contains("UNIQUE ID1"));
}
}
公共类TestClass{
私有静态类内部类{
私有最终字符串testKey;
//数据等
InnerClass(字符串testKey,int-dataStuff){
this.testKey=testKey;
//等
}
@凌驾
公共布尔等于(中的对象){
System.out.println(“到达此处”);
if(in==null){
返回false;
}else if(在instanceof字符串中){
字符串inString=(字符串)in;
返回testKey==null?false:testKey.equals(inString);
}否则{
返回false;
}
}
}
公共静态void main(字符串[]args){
ArrayList objectList=新建ArrayList();
//添加一些条目
add(新的内部类(“惟一ID1”,42));
System.out.println(objectList.contains(“惟一ID1”);
}
}
让我担心的是,我不仅在输出上出错,而且没有得到“到达此处”的输出
有人知道为什么这个覆盖被完全忽略了吗?覆盖和内部类是否有一些我不知道的微妙之处
编辑:
有问题的网站,所以我似乎无法标记答案。
感谢您的快速回复:是的,我的疏忽是调用了字符串.equals thta,而不是我的自定义字符串。我想现在是老式支票了虽然没有回答你的问题,但许多收藏都使用了
hashcode()
。您也应该覆盖它,以便“同意”使用equals()
实际上,您应该始终同时实现equals
和hashcode
,并且它们应该始终保持一致。正如Object.equals()
的javadoc所述:
请注意,通常有必要
无论何时重写hashCode方法
此方法被重写,以便
维护项目的总合同
hashCode方法,该方法声明
相等的对象必须具有相等的哈希
代码
具体地说,许多集合依赖于支持此契约-否则行为未定义。您正在调用的
包含,其参数是字符串,而不是内部类
:
System.out.println( objectList.contains("UNIQUE ID1"))
在我的JDK中:
public class ArrayList {
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
// omitted for brevity - aix
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i])) // <<<<<<<<<<<<<<<<<<<<<<
return i;
}
return -1;
}
}
公共类数组列表{
公共布尔包含(对象o){
返回索引of(o)>=0;
}
public int indexOf(对象o){
如果(o==null){
//为简洁起见省略-aix
}否则{
对于(int i=0;i 如果(o.equals(elementData[i])/检查ArrayList
的源,您将看到它调用其他对象的equals
。在您的情况下,它将调用字符串的equals
“UNIQUE ID1”
,这将检查其他对象的类型是否为字符串
,并且只返回false
:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
...
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
...
return -1;
}
不要忘记为只比较id
的内部类实现equals
。根据,它被定义为返回true
当且仅当此列表包含至少一个元素e
,从而(o==null?e==null:o.equals(e))
请注意,此定义在o
上调用equals
,它是参数,而不是列表中的元素
因此将调用String.equals()
,而不是InnerClass.equals()
还要注意的是
它是对称的:对于任何非空参考值x
和y
,x.equals(y)
应返回true
当且仅当y.equals(x)
返回true
时
但是您违反了这个约束,因为newtestclass(“foo”,1).equals(“foo”)
返回true
但“foo”。equals(newtestclass(“foo”,1))
将始终返回false
不幸的是,这意味着您的用例(可以等同于另一个标准类的自定义类)不能以完全一致的方式实现
如果您仍然想做这样的事情,您必须非常仔细地阅读所有集合类的规范(有时是实现),并检查这样的陷阱。通常,您还需要覆盖hashCode()
但这不是这里的主要问题。您有一个不对称的equals(…)
方法。文档明确指出它应该是对称的:
它是对称的:对于任何非空的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true
你所观察到的是由于合同破裂而导致的意外行为
创建一个实用程序方法,该方法迭代所有项,并在字符串上使用equals(..)
进行验证:
public static boolean containsString(List<InnerClass> items, String str) {
for (InnerClass item : items) {
if (item.getTestKey().equals(str)) {
return true;
}
}
return false;
}
equals实现错误。in参数不应该是字符串
。它应该是内部类
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof InnerClass) return false;
InnerClass that = (InnerClass)o;
// check for null keys if you need to
return this.testKey.equals(that.testKey);
}
(请注意,instanceof null
返回false,因此不需要先检查null)
然后,您将使用以下方法测试列表中是否存在等效对象:
objectList.contains(new InnerClass("UNIQUE ID1"));
但是,如果您真的想通过字符串键检查InnerClass,为什么不使用Map
来代替呢?您的代码有一些问题。我的建议是,如果您不熟悉它,就避免完全覆盖equals,并将其扩展到一个新的实现中,就像这样
class MyCustomArrayList extends ArrayList<InnerClass>{
public boolean containsString(String value){
for(InnerClass item : this){
if (item.getString().equals(value){
return true;
}
}
return false;
}
}
我建议这样做是因为如果你覆盖了equals,那么它也应该覆盖hashCode,而且你似乎缺乏一点关于hashCode的知识
objectList.contains(new InnerClass("UNIQUE ID1"));
class MyCustomArrayList extends ArrayList<InnerClass>{
public boolean containsString(String value){
for(InnerClass item : this){
if (item.getString().equals(value){
return true;
}
}
return false;
}
}
List myList = new MyCustomArrayList()
myList.containsString("some string");
package com.test;
import java.util.ArrayList;
import java.util.List;
public class TestClass {
private static class InnerClass{
private final String testKey;
//data and such
InnerClass(String testKey, int dataStuff) {
this.testKey =testKey;
//etc
}
@Override
public boolean equals (Object in1) {
System.out.println("reached here");
if(in1 == null) {
return false;
}else if( in1 instanceof InnerClass) {
return ((InnerClass) this).testKey == null ? false : ((InnerClass) this).testKey.equals(((InnerClass) in1).testKey);
}else {
return false;
}
}
}
public static void main(String[] args) {
ArrayList<InnerClass> objectList = new ArrayList<InnerClass>();
InnerClass in1 = new InnerClass("UNIQUE ID1", 42);
InnerClass in2 = new InnerClass("UNIQUE ID1", 42);
//add some entries
objectList.add(in1);
System.out.println( objectList.contains(in2));
}
}
public static InnerClass empty(String testKey) {
InnerClass in = new InnerClass();
in.testKey =testKey;
return in;
}
ind position = list.indexOf(InnerClass.empty(key));
@Override
public boolean equals (Object in) {
System.out.println("reached here");
if(in == null) {
return false;
}else if( in instanceof InnerClass) {
String inString = ((InnerClass)in).testKey;
return testKey == null ? false : testKey.equals(inString);
}else {
return false;
}
}
System.out.println(objectList.stream().filter(obj -> obj.getTestKey().equals("UNIQUE ID1")).findAny().isPresent());
public String getTestKey() {
return testKey;
}