我有两个对象,需要比较它们的属性。该代码当前使用很长的if / else语句序列来逐步访问属性。
要解决这个问题吗?
例如,它看起来像:
if (car.getIsElectric() && (!parkingGarage.getIsElectric())) {
log("Electric cars are not permitted here");
return 1;
}
if (car.getIsSuv() && (!parkingGarage.getIsSuv())) {
log("SUVs are not allowed in.");
return 1;
}
...
此问题类似于: Comparing the properties of two objects 我想看看Java是否存在等效形式。
答案 0 :(得分:1)
您可以反射性地遍历对象中的每个字段。我的示例假定这两个对象具有相同的确切类型,但是我敢肯定,您可以对其进行改进以比较同一类层次结构中的两个不同对象。
public class Vehicle {
public int width, height;
public Vehicle(int int1, int int2) {
this.width = int1;
this.height = int2;
}
public static void main(String[] args) {
Vehicle vehicle1 = new Vehicle(5, 10), vehicle2 = new Vehicle(5, 10), vehicle3 = new Vehicle(5, 20);
System.out.println(equal(vehicle1, vehicle2));
System.out.println(equal(vehicle2, vehicle3));
System.out.println(equal(vehicle1, vehicle3));
}
public static boolean equal(Vehicle first, Vehicle other) {
for (Field f : Vehicle.class.getDeclaredFields()) {
try {
if (!f.get(first).equals(f.get(other)))
return false;
} catch (IllegalArgumentException e) {
// Method callers can only pass in Test objects to this method, so this
// shouldn't be thrown either. Watch out for callers passing in null to this
// method though.
e.printStackTrace();
} catch (IllegalAccessException e) {
// Fields are public and this method belongs to Test, so this shouldn't be
// thrown.
e.printStackTrace();
}
}
return true;
}
}
以上代码的主要部分是静态equal
方法。它比较每个对象上的每个Field
(在Vehicle
中声明的),如果不相等,则返回false。如果您还想比较Vehicle
的继承字段,则可以使用getFields()
代替getDeclaredFields()
。
简而言之,我认为您正在寻找的代码类型是:
for (Field f : Vehicle.class.getDeclaredFields())
try {
if (!f.get(first).equals(f.get(other)))
return false;
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
return true;
(顺便说一句,我更喜欢“无限序列”:))
答案 1 :(得分:0)
注意: 该答案适用于原始问题,比较两个相同类型的对象,不适用于检查访问权限的更新问题规则。
要比较带有大量if
语句的两个对象,我们将使用一个带有3个字段的Vehicle
对象作为示例:
class Vehicle {
private final String type;
private final int wheelCount;
private final boolean electric;
}
您已经知道,您必须为每个写一个setter(或构造函数)和getter,所以您已经有“重复性工作”要做,所以请放心:
public Vehicle(String type, int wheelCount, boolean electric) {
this.type = type;
this.wheelCount = wheelCount;
this.electric = electric;
}
public String getType() {
return this.type;
}
public int getWheelCount() {
return this.wheelCount;
}
public boolean isElectric() {
return this.electric;
}
和标准方法:
@Override
public int hashCode() {
int hash = this.type.hashCode();
hash = hash * 31 + this.wheelCount;
hash = hash * 3 + (this.electric ? 1 : 2);
return hash;
}
@Override
public boolean equals(Object obj) {
if (! (obj instanceof Vehicle))
return false;
Vehicle that = (Vehicle) obj;
return (this.type.equals(that.type)
&& this.wheelCount == that.wheelCount
&& this.electric == that.electric);
}
所以现在您可以简单地做:
if (! car.equals(bus)) {
return 1;
}
那是唯一的if
语句。
答案 2 :(得分:-1)
您需要做的第一件事就是让您的类实现Comparable Interface。如果您的类创建复合对象(包含其他对象的对象),则这些对象中的每个对象也必须实现可比较的接口。您需要做的第二件事是重写Object.equals(Object)
和Object.hashCode()
方法。您的示例正在创建一个静态equals
方法,我强烈建议您不要这样做。就像我之前为实现Comparable
所提到的那样,所有对象引用的类都必须覆盖equals
和hashCode
。
可比接口只有一个方法:compareTo(T t)
。此方法的目的是比较两个对象,以确定两个对象是否相似(但不相同)。例如,如果两个车辆的制造商/型号相同,制造年份相同,具有相同的选件,发动机,车轮等,但具有不同的VIN编号,则可以说它们是相似的。基本上,这两辆车的外观相同,但并非完全相同。同时,equals
和hashCode
方法的目的是建立对象实例相等性。
下面以相同的示例为例,您说您报警是因为您的车辆被盗了。警察会收集有关您汽车的所有信息,他们将调查所有与车辆描述相符的汽车(看起来像您的汽车)。但是,通过查找VIN号,他们会确定该车不是您的车。所以基本上....
yourVehicle.compareTo(suspiciousVechile); // return true
yourVehicle.equals(suspiciousVehicle); // returns false
尽管在Comparable
接口Javadoc中不建议这样做,但是在某些情况下,compareTo
的真实结果可能会产生与equals
不同的结果。这适用于一个对象是另一个对象的副本,但它们是不同实例的情况。有时候这个事实很重要;尽管通常不是。
我建议您研究一下Java的String类,看看它们如何同时使用两种方法(compareTo和equals)。忽略equals
在内部不调用compareTo
的事实。
答案 3 :(得分:-1)
对于两个任意对象,您可以反射性地迭代其中一个对象中的字段,以查看两个对象均具有1:1的字段。然后,您可以比较这些字段。
有关快速解决方案,请检查以下内容。
这是一个非常大且可能令人讨厌的示例:
class Test {
public static Field getFieldSafely(String fieldName, Object object) {
Field[] fields = object.getClass().getFields();
for (Field f : fields)
if (f.getName().equals(fieldName))
return f;
return null;
}
public static boolean equal(Object first, Object other) {
for (Field f : first.getClass().getFields()) {
String fieldName = f.getName();
Field otherField = getFieldSafely(fieldName, other);
if (otherField != null)
try {
if (!f.get(first).equals(otherField.get(other)))
return false;
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
return true;
}
public static void main(String[] args) {
Vehicle vehicle1 = new Vehicle(5, 10), vehicle2 = new Vehicle(5, 10), vehicle3 = new Vehicle(5, 20);
Box box1 = new Box(5, 10), box2 = new Box(100, 200);
System.out.println(equal(vehicle1, vehicle2));// True
System.out.println(equal(vehicle2, vehicle3));// False
System.out.println(equal(vehicle1, vehicle3));// False
System.out.println(equal(box1, box2));// False
System.out.println(equal(vehicle1, box1));// True
}
}
class Box {
public int width, height;
public Box(int width, int height) {
this.width = width;
this.height = height;
}
}
class Vehicle {
public int width, height, weight;
public Vehicle(int int1, int int2) {
this.width = int1;
this.height = int2;
}
}
最重要的方法在Test
类中。方法equal(...)
接受两个对象。然后,它检查第一个对象中的每个字段是否包含在第二个对象中。对于它在第一个对象中找到的,与第二个对象中的字段同名的每个字段,将检查这些字段是否相等。如果在两个对象中找到的所有字段都相等,则该方法返回true
。否则,它将返回false
。
这是重要的方法。您可以根据需要修改它们,以满足您的需求。
如果在给定对象中找不到具有给定名称的字段,则 getFieldSafely(...)
仅返回null。否则,它将返回该字段。
public static Field getFieldSafely(String fieldName, Object object) {
Field[] fields = object.getClass().getFields();
for (Field f : fields)
if (f.getName().equals(fieldName))
return f;
return null;
}
public static boolean equal(Object first, Object other) {
for (Field f : first.getClass().getFields()) {
String fieldName = f.getName();
Field otherField = getFieldSafely(fieldName, other);
if (otherField != null)
try {
if (!f.get(first).equals(otherField.get(other)))
return false;
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
return true;
}
祝你好运。 :)