在 class 之外覆盖 Object#equals(Object)
Overriding Object#equals(Object) outside the class
使用 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)
时想要另一种 equals 怎么办?例如我想知道一个列表是否包含某个名字?是否可以覆盖 Object#equals(Object)
'anonymously'?
更具体的解释为什么我需要它:
int objectId = ... // Some event which passes me the attribute of an object but not the object itself
现在我有 List<SomeObject> someObjects
,我想知道这个列表是否包含带有 objectId
的对象,而不必对其进行迭代。
我能想到的一个 "solution" 会使用 Map<Integer, SomeObject> mapping
然后 someObject = mapping.get(objectId)
编辑: 我的问题不是重复的,因为我特别要求覆盖 Object#equals(Object)
.
您可以对从列表中获得的流对象应用过滤器。过滤器采用谓词,您可以在其中设置条件。然后你可以检查过滤后的流是否不为空:
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();
}
并按如下方式调用它:
boolean containsElement = containsWithPredicate(myListOfObjects,
(e -> e.name.equals(otherName)));
编辑:
有一种更简单的方法可以通过调用 Stream.anyMatch
而不是先调用 filter
然后调用 findAny
:
list.stream().anyMatch(predicate);
您可以使用带有自定义 Comparator
的 TreeSet
来实现您想要的效果。它不使用 equals()
表示相等,而是认为如果 compare()
returns 0
,对象是相等的。
假设我们希望所有 Strings
都相等,前提是它们的长度相同:
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
如果您需要在不同的时间对对象使用不同的 "equality definitions",同时仍然使用集合,这可能是一个有用的构造(也适用于 TreeMap
)。
同一个 class 不可能有多个 equals
。但是您可以 subclass 您的 class 并覆盖 hashCode()
和 equals()
,然后根据 [=10] 使用所需的实例=]你想用。
我必须说我不喜欢这样做,equals
方法应该定义得很好,在不同的场景下使用多个 equals
会很混乱。如果我需要两种不同的 equals
方法,我将采用完全不同的实现而不是 subclassing。所以我强烈建议你重新考虑你的设计。
使用 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)
时想要另一种 equals 怎么办?例如我想知道一个列表是否包含某个名字?是否可以覆盖 Object#equals(Object)
'anonymously'?
更具体的解释为什么我需要它:
int objectId = ... // Some event which passes me the attribute of an object but not the object itself
现在我有 List<SomeObject> someObjects
,我想知道这个列表是否包含带有 objectId
的对象,而不必对其进行迭代。
我能想到的一个 "solution" 会使用 Map<Integer, SomeObject> mapping
然后 someObject = mapping.get(objectId)
编辑: 我的问题不是重复的,因为我特别要求覆盖 Object#equals(Object)
.
您可以对从列表中获得的流对象应用过滤器。过滤器采用谓词,您可以在其中设置条件。然后你可以检查过滤后的流是否不为空:
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();
}
并按如下方式调用它:
boolean containsElement = containsWithPredicate(myListOfObjects,
(e -> e.name.equals(otherName)));
编辑:
有一种更简单的方法可以通过调用 Stream.anyMatch
而不是先调用 filter
然后调用 findAny
:
list.stream().anyMatch(predicate);
您可以使用带有自定义 Comparator
的 TreeSet
来实现您想要的效果。它不使用 equals()
表示相等,而是认为如果 compare()
returns 0
,对象是相等的。
假设我们希望所有 Strings
都相等,前提是它们的长度相同:
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
如果您需要在不同的时间对对象使用不同的 "equality definitions",同时仍然使用集合,这可能是一个有用的构造(也适用于 TreeMap
)。
同一个 class 不可能有多个 equals
。但是您可以 subclass 您的 class 并覆盖 hashCode()
和 equals()
,然后根据 [=10] 使用所需的实例=]你想用。
我必须说我不喜欢这样做,equals
方法应该定义得很好,在不同的场景下使用多个 equals
会很混乱。如果我需要两种不同的 equals
方法,我将采用完全不同的实现而不是 subclassing。所以我强烈建议你重新考虑你的设计。