Java 重写类外的Object#equals(Object)
使用Java 重写类外的Object#equals(Object),java,equals,Java,Equals,使用list.contains(someObject)时,是否可以在本地重写Object#equals(Object) 示例: class SomeObject { ... private int id; private String name; @Overrdide public boolean equals(Object other){ ... return this.id == other.id; } }
list.contains(someObject)
时,是否可以在本地重写Object#equals(Object)
示例:
class SomeObject {
...
private int id;
private String name;
@Overrdide
public boolean equals(Object other){
...
return this.id == other.id;
}
}
int objectId = ... // Some event which passes me the attribute of an object but not the object itself
但是当我使用list.contains(someObject)
时,如果我想要另一种类型的equals呢?例如,我想知道列表是否包含某个名称?是否可以“匿名”覆盖Object#equals(Object)
更具体地解释我为什么需要它:
class SomeObject {
...
private int id;
private String name;
@Overrdide
public boolean equals(Object other){
...
return this.id == other.id;
}
}
int objectId = ... // Some event which passes me the attribute of an object but not the object itself
现在我有了List someObjects
,我想知道这个列表是否包含一个带有objectId
的对象,而不必对它进行迭代
我能想到的一个“解决方案”是使用Map-mapping
,然后使用someObject=mapping.get(objectId)
编辑:我的问题不是重复的,因为我特别要求覆盖
对象#等于(对象)
您可以对从列表中获得的流对象应用过滤器。过滤器接受一个谓词,您可以在其中设置条件。然后,您可以检查过滤后的流是否为空:
list.stream().filter(e -> e.name.equals(otherName)).findAny().isPresent()
您可以按如下方式使其可重用,例如:
private <T> boolean containsWithPredicate(List<T> list, Predicate<T> predicate) {
return list.stream().filter(predicate).findAny().isPresent();
}
编辑:
class SomeObject {
...
private int id;
private String name;
@Overrdide
public boolean equals(Object other){
...
return this.id == other.id;
}
}
int objectId = ... // Some event which passes me the attribute of an object but not the object itself
有一种简单得多的方法可以实现与上面完全相同的功能,方法是只调用,而不是执行filter
然后执行findAny
:
list.stream().anyMatch(predicate);
您可以将
树集
与自定义的比较器
一起使用,以实现所需的功能。它不使用equals()
表示相等,而是考虑如果compare()
返回0
,则对象相等
假设我们希望所有长度相同的字符串都相等:
TreeSet<String> set = new TreeSet(new Comparator<>() {
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}
set.add("asd");
set.contains("foo"); // Returns true
TreeSet集=新树集(新比较器(){
公共整数比较(字符串o1、字符串o2){
返回o1.length()-o2.length();
}
}
设置。添加(“asd”);
set.contains(“foo”);//返回true
这是一个有用的构造(也适用于TreeMap
),当您需要在不同的时间为对象创建不同的“相等定义”时,同时仍然使用集合。对于同一个类,没有办法让多个相等。但是您可以对类进行子类化并重写hashCode>()
和equals()
,然后根据要使用的equals
使用所需的实例
我必须说,我不喜欢这样做,equals
方法应该得到很好的定义,在不同的场景中使用多个equals
将非常混乱。如果需要两个不同的equals
方法,我将使用完全不同的实现,而不是子类化。因此,我强烈建议您重新考虑您的设计。不确定这是一个解决方案还是一个变通方法,因为我也可以使用for-each循环进行迭代。但这绝对是一种方法。@SklogW我认为这是一个解决方案。需要一个“等于”匿名方法,可以自定义,所以首先想到的是函数式编程(可以将筛选器的谓词作为参数传递)。它看起来也更容易阅读。@SklogW这是您实际想要做的。如果您不想创建一个新的equals
方法,您需要检查列表是否包含基于特定参数的内容,为此您需要一个-,这实际上就是方法中的lambda。特别是因为一个新的equals意味着我会更改对象的标识。你的方法清楚地表明了我的意图。Thx!我有点惊讶,没有findAny
接受谓词。LINQ中的等价物是,它有两个重载。一个接受谓词,另一个不接受。这样你就不必做Where
和Any
(或filter
和findAny
)作为两个不同的操作。这应该是,但这是collections API最糟糕的地方。您可以在许多地方使用自定义比较器,但您只能使用一个等于
的概念。如果Java只有case类:-(使用比较器指定相等对集合和映射键有效(但会损害性能-操作变为O(logn),因为必须使用TreeMap而不是HashMap)。但这对列表没有帮助。应该可以使用自定义的相等概念与方法,如indexOf
,contains
等,但如果不创建包装类并根据需要重写等于,则不可能。这非常烦人。@SklogW列表有多大?如果您对顺序和一个属性不感兴趣如果多次查询,您可以使用特定于此属性的比较器对列表重新排序,然后检查Collections.binarySearch(list,cmp)>=0
是否不重复,因为我专门询问了重写equals().复制是隐含的IMHO。但它仍然会给我一个列表,其中有一个关于什么是相等的或不相等的永久定义,对吗?如果我只想要某类相等的值一次怎么办?我可以更改比较器吗?例如,它会定义“什么是相等的”对于该集合。您可以编写比较器
,以便它对不同的对象具有不同的逻辑,但它将更容易出错,您需要确保遵守compare()
的合同。很好的建议。如果我需要不同的equals,那么可能是我的设计问题。我会考虑这个问题。@SklogW这是个好主意。想想其他可能使用你的程序的程序员,他们怎么知道要选择什么实现?equals
应该定义得很好。这很有意义。我想我正在努力工作围绕着一个糟糕的设计。谢谢!