我有一个Java类,这是一个例子:
public class Car {
private int fuelType;
private Date made;
private String name;
.
.
. // and so on
现在假设我有两个车对象,我想比较它们的所有变量是否相等。
现在,我通过重写方法equals(Object o)
解决了这个问题,并检查两个对象中的所有变量是否匹配。
这里的问题是,如果我有20个课程,我将不得不在每个课程中覆盖equals(Object o)
。
有没有办法创建某种通用方法,可以比较我传递给它的两个对象中的任何一个,并让我知道它们是否匹配每个变量?
答案 0 :(得分:22)
您可以选择使用Equals& amp; Hashcode(选项#3 BLEW MY MIND!):
EqualsAndHashCode
注释并完成它。 我建议使用Project Lombok 。它为构建添加了一些魔力(但并不多),因此需要一个IDE的插件才能很好地运行,但它们是一个很小的代价,无需样板代码。 Lombok是一个在编译时运行的注释处理器,因此您不会遇到运行时性能损失。 答案 1 :(得分:4)
你可以使用:
org.apache.commons.lang.builder.CompareToBuilder.reflectionCompare(Object lhs, Object rhs);
它使用反射来比较文件 这是javadoc:javadoc
答案 2 :(得分:4)
我会对大多数人持反对意见(在反思中使用apache commons):是的,这是你必须写的一些代码(让你的IDE真正生成),但你只需要做一次,需要实现equals / hashcode的数据类的数量通常是可管理的 - 至少在我工作的所有大型项目(250k + LOC)中都是如此。
当然,如果您向该类添加一个新成员,您将不得不记住更新equals / hashcode函数,但这通常很容易注意到,最迟在代码审查期间。
老实说,如果你使用一个简单的小助手类,甚至在Java7中,你可以减少Wana Ant显示的代码。真正需要的是:
@Override
public boolean equals(Object o) {
if (o instanceof Car) { // nb: broken if car is not final - other topic
Car other = (Car) o;
return Objects.equals(fuelType, other.fuelType) &&
Objects.equals(made, other.made) &&
Objects.equals(name, other.name);
}
return false;
}
类似于hashcode:
@Override
public int hashCode() {
return Objects.hash(fuelType, made, name);
}
不像反射解决方案那么短吗?没错,但它很简单,易于维护,适应和读取 - 性能要好一些(对于实现equals和hashcode的类通常很重要)
答案 3 :(得分:3)
通常,您可以通过IDE生成equals / hashCode方法 - 此领域的所有大型参与者都能够(Eclipse,IntelliJ Idea和Netbeans)。
通常,您可以创建一些使用反射的代码,但我不建议使用反射,因为客观方法更清晰,更易于维护。反射也不会像“标准”那样快。如果你真的想这样,那就有EqualsBuilder和HashCodeBuilder等实用程序。
仅供参考,有基于JVM的语言已经支持这些功能,例如: Kotlin data classes,可以很好地用于现有的Java项目中。
答案 4 :(得分:2)
我会为我最喜欢的解决方案插入一个插件:@AutoValue
。
这是Google提供的一个开源项目,它提供了一个注释处理器,可以为您生成实现equals
和hashCode
的合成类。
由于它是自动生成的代码,因此您无需担心会意外忘记字段或弄乱equals
或hashCode
实施。但由于代码是在编译时生成的,因此运行时开销为零(与基于反射的解决方案不同)。它也是“API不可见” - 你班级的用户无法区分@AutoValue
类型和你自己实现的类型,并且你可以在不打破来电者的情况下来回改变。
另见this presentation,它解释了基本原理,并将其与其他方法相比做得更好。
答案 5 :(得分:1)
从理论上讲,你可以使用反射来创建某种类型的util,正如许多人在评论中建议的那样。就个人而言,我不建议你这样做。你会得到一些部分有效的东西。
Java中的许多内容都依赖于equal
或hashCode
,例如方法contains
,您可以在实现Collection
的任何内容中找到它。
建议覆盖equal
(和hashCode
)。此外,我认为任何体面的IDE都可以选择为您生成它们。因此,您可以比使用反射更快地完成它。
答案 6 :(得分:0)
这就是我这样做的方式:
@Override
public boolean equals(Object obj) {
if (obj instanceof Car) {
return internalEquals((Car) obj);
}
return super.equals(obj);
}
protected boolean internalEquals(Car other) {
if(this==other){
return true;
}
if (other != null) {
//suppose fuelType can be Integer.
if (this.getFuelType() !=null) {
if (other.getFuelType() == null) {
return false;
} else if (!this.getFuelType().equals(other.getFuelType())) {
return false;
}
} else if(other.getFuelType()!=null){
return false;
}
if (this.getName() != null) {
if (other.getName() == null) {
return false;
} else if (!this.getName().equals(other.getName())) {
return false;
}
}
else if(other.getName()!=null){
return false;
}
if (this.getDate() != null) {
if (other.getDate() == null) {
return false;
} else if (!this.getDate().getTime()!=(other.getDate().getTime())) {
return false;
}
}
else if(other.getDate()!=null){
return false;
}
return true;
} else {
return false;
}
}
编辑
简化版
public class Utils{
/**
* Compares the two given objects and returns true,
* if they are equal and false, if they are not.
* @param a one of the two objects to compare
* @param b the other one of the two objects to compare
* @return if the two given lists are equal.
*/
public static boolean areObjectsEqual(Object a, Object b) {
if (a == b){
return true;
}
return (a!=null && a.equals(b));
}
public static boolean areDatesEqual(Date a, Date b){
if(a == b){
return true;
}
if(a==null || b==null){
return false;
}
return a.getTime() == b.getTime();
}
}
@Override
public boolean equals(other obj) {
if(this == other){
return true;
}
if(other == null){
return false;
}
if (other instanceof Car) {
return internalEquals((Car) other);
}
return super.equals(obj);
}
protected boolean internalEquals(Car other) {
//suppose fuelType can be Integer.
if (!Utils.areObjectsEqual(this.getName(), other.getName()){
return false;
}
if (!Utils.areObjectsEqual(this.getName(), other.getName()){
return false;
}
if (!Utils.areDatesEqual(this.getDate(), other.getDate()){
return false;
}
return true;
}
}
也不要忘记哈希码,他们手拉手编码。