我需要检查特定对象的等效实例是否在List中。
对象是具有等于太严格的等于方法的Final Class的实例。我希望能够为{contains}方法提供equals
的不同实现,以检查对象是否包含在List中。
如果partsInBox
的元素的顺序不同,则下面类中的equals方法将返回false;我需要将此行为更改为不加选择的顺序。
public final class Box {
String category;
List<Integer> partsInBox;
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Box box = (Box) o;
return category.equals(box.category)
&& partsInBox.equals(box.partsInBox);
}
}
我希望能够做到这样的事情:
List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for
boolean contained = contatins(boxes, box, new EqualsMethod() {
@Override
public boolean areEqual(Box b1, Box b2) {
if (b1 == b2) { return true; }
return b1.category.equals(b2.category)
&& b1.partsInBox.containsAll(b2.partsInBox);
}
});
我有哪些选择来实现此类功能?
答案 0 :(得分:2)
理想的解决方案是改变equals()方法的当前行为。但是,如果您无权访问其他代码,则可能无法使用。
相反,您可以使用Apache CollectionUtils中的CollectionUtils.exists(collection, predicate)
。
您可以使用自定义条件创建谓词,以确定对象是否足够。
希望它有所帮助。
答案 1 :(得分:1)
因为课程是final
所以你不能扩展它。
然而,您可以使用Comparator<T>
接口,如下所示:
public class BoxComparator implements Comparator<Box> {
@Override
public int compare(Box b1, Box b2) {
if (b1 == b2) { return 0; }
// return -1 or 0 or +1...
}
public static void main(String[] args) {
Box box1, box2;
...
boolean contains = new BoxComparator().compare(box1, box2) == 0;
}
}
如果您想将Box
与另一个Box
或List<Box>
进行比较,我不能完全确定上面的代码示例 - 在后一种情况下,您无法导出{ {1}},但您可以执行类似的操作,例如Comparator
。
希望这有帮助。
答案 2 :(得分:1)
<强> Equator.java 强>
public interface Equator<T> {
boolean equals(T obj1, T obj2);
}
其他一些课程
public static <T> boolean contains(Collection<T> toSearch, T toSeek, Equator<T> equator) {
for (T oneItem : toSearch) {
if (equator.equals(oneItem, toSeek)) {
return true;
}
}
return false;
}
使用
import static some.other.class.contains; // The contains method from the class above
List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for
boolean contained = contains(boxes, box, new Equator<Box>() {
@Override
public boolean equals(Box b1, Box b2) {
if (b1 == b2) { return true; }
return b1.category.equals(b2.category)
&& b1.partsInBox.containsAll(b2.partsInBox);
}
});
答案 3 :(得分:0)
您可以使用具有Java内置方法的Comparator进行排序和二分查找。假设您有一个这样的类,其中a和b是您要用于排序的字段:
class Thing { String a, b, c, d; }
您可以定义比较器:
Comparator<Thing> comparator = new Comparator<Thing>() {
public int compare(Thing o1, Thing o2) {
if (o1.a.equals(o2.a)) {
return o1.b.compareTo(o2.b);
}
return o1.a.compareTo(o2.a);
}
};
然后对列表进行排序:
Collections.sort(list,comparator); 最后进行二分搜索:
int i = Collections.binarySearch(list, thingToFind, comparator);
答案 4 :(得分:0)
使用Closures在Groovy中会更容易(但不是那么显然效率低下)。好吧,我们进入Java:
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// ------- Original code with comments added
public final class Box {
// these should be final and List<Integer> should be immutable using
// Collections.unmodifiableList() to avoid nasty surpises, and should
// possibly be pre-sorted
String category;
List<Integer> partsInBox;
@Override
public boolean equals(Object o) {
// same instance, then true (works if null passed, too)
if (this == o) {
return true;
}
// Null and not exactly same class (instanceof not needed as "final"), then false
if (o == null || getClass() != o.getClass()) {
return false;
}
Box box = (Box) o;
// otherwise same category and exactly same list (including ordering)
return category.equals(box.category) && partsInBox.equals(box.partsInBox);
}
}
// ------- Create a wrapper class around Box, repainting the house
class WrappedBox {
final Box box;
WrappedBox(Box box) {
assert box != null;
this.box = box;
}
public String getCategory() {
return box.category;
}
public List<Integer> getPartsInBox() {
return box.partsInBox;
}
public boolean equals(Object o) {
// same instance, then true (works if null passed, too)
if (this == o) {
return true;
}
// Null and not same class, then false
if (o == null || !(o instanceof WrappedBox)) {
return false;
}
//
// otherwise same category and the set of b1 parts is a superset of the set of b2 parts
// this is not symmetric; should probably be a set comparison. What happens if there
// are several integers with the same value??
// return b1.category.equals(b2.category)
// && b1.partsInBox.containsAll(b2.partsInBox);
//
// SO RECODE AS AUXILIARY EXERCISE:
//
WrappedBox other = (WrappedBox)o;
if (!this.getCategory().equals(other.getCategory())) {
return false;
}
//
// You probably want to buffer these somehow:
//
List<Integer> x1 = new ArrayList(this.getPartsInBox());
List<Integer> x2 = new ArrayList(other.getPartsInBox());
Collections.sort(x1);
Collections.sort(x2);
return x1.equals(x2);
}
}
// --------- Now we can ask for "contains", though one should really create a
// ---------- List<WrappedBox> first if this happens often
class BoxHandler {
static boolean containsBox(List<Box> boxes, Box box) {
assert box != null;
assert boxes != null;
WrappedBox wbox = new WrappedBox(box);
for (Box cur : boxes) {
if (wbox.equals(new WrappedBox(cur))) {
return true;
}
}
return false;
}
}
答案 5 :(得分:0)
您无法提供其他方法来与List进行比较。最好和最简单的解决方案是修改你的equals()方法。如果你不能修改equals,你可以实现一个Decorator类来创建一个包含你需要的areEquals比较的列表。
public class BoxList<E extends Box> implements List<E>{
private List<E> list;
public BoxList(List<E> list) {
this.list = list;
}
//Modify the behavior of the methods
@Override
public boolean contains(Object o) {
for(E element : list) {
if (element.areEquals(o)) {
return true;
}
}
return false;
}
// Redirect all other List methods to the original list
@Override
public boolean add(E e) {
return list.add(e);
}
@Override
public void add(int index, E element) {
list.add(index, element);
}
...