我有一个重写equals()
和hashCode()
的抽象类。在这些方法中,我使用抽象方法getDescription()
来检查是否相等并生成hashCode。现在,当我扩展类并添加仅在getDescription()
方法中使用的字段时,出现了sonarLint问题“扩展了一个覆盖等于并添加字段的类”。只是Sonar不够复杂,无法理解正在发生的事情,还是我以非Java方式进行操作,并且有更好/更优雅的方式?
父类:
public abstract String getDescription();
@Override
public int hashCode()
{
return new HashCodeBuilder(19, 71).
append(mViolation).
append(getDescription()).
append(mProperties).
toHashCode();
}
@Override
public boolean equals(
final Object obj)
{
boolean equal = false;
if (this == obj)
{
equal = true;
}
else if (obj instanceof parent)
{
AbstractStructuredDataIssue rhs = (parent) obj;
equal = new EqualsBuilder().
append(mViolation, rhs.mViolation).
append(getDescription(), rhs.getDescription()).
append(mProperties, rhs.mProperties).
isEquals();
}
return equal;
}
儿童班:
public class Child extends Parent {
private final String mMessage;
public Child(final String message, final int number) {
super(number);
mMessage = message;
}
@Override
public String getDescription()
{
return String.format(
DESCRIPTION_FORMAT,
mMessage);
}
}
答案 0 :(得分:0)
这有点复杂;我必须解释一些有关equals和hashCode如何工作以解释可行解决方案的事情。
有一个“合同”。编译器无法强制执行它,但是如果您不遵守此合同,将会发生奇怪的事情。特别是:当您的对象在哈希图中用作键时,只会做错事,而在使用第三方库时,可能还会发生其他此类问题。为了正确遵守合同,任何给定的类要么需要完全退出equals / hashCode,要么整个链(因此,该类及其所有子类)都必须正确地覆盖hashCode和equals,除非您确实可以除非父母有适当的条件,否则不要这样做。
合同规定这必须始终是正确的:
面对类层次结构,合同真的很难保证!想象一下,我们采用现有的java.util.ArrayList并使用“颜色”的概念对其进行子类化。现在我们可以有一个蓝色的ColoredArrayList或红色的ColoredArrayList。最好说一个蓝色ColoredArrayList绝对不应该等于红色ColoredArrayList,除非.. ArrayList本身的equals impl(您不能更改),有效地定义了您不能简单地使用此类属性扩展ArrayList :如果您调用a.equals(b),其中a是一个空数组列表,b是一些空列表(例如,一个空的红色ColoredArrayList),它将只检查其中的每个成员是否相等, ,因为它们都是空的,所以确实是正确的。因此,空的正常arraylist等于空的红色和空的蓝色ColoredArrayList,因此合同规定空的红色ColoredArrayList必须等于空的蓝色ColoredArrayList。从这个意义上讲,声纳在这里就被打破了。有一个问题,它是无法修复的。 不可能用Java编写ColoredArrayList的概念。
尽管如此,有一个解决方案,但前提是层次结构中的每个类都已加入。这是canEqual
方法。摆脱上述彩色困境的方法是区分“我正在扩展,并添加新属性”和“我正在扩展”的概念,但是,从语义上讲,这些事情仍然是完全相同的事情,没有新属性。 ColoredArrayList是前一种情况:它是添加新属性的扩展。 canEqual的想法是,您创建一个单独的方法来表明这一点,这使ArrayList能够确定:即使所有元素都相同,我也不能等于ANY ColoredArrayList实例。然后,我们可以再次遵守合同。 ArrayList没有该系统,因此,鉴于您无法更改ArrayList的源代码,您将陷入困境:它不可修复。但是,如果您编写自己的类层次结构,则可以添加它。
Lombok项目负责为您添加equals和hashCode。即使您不想使用它,也可以查看它生成的内容并将其复制到您自己的代码中。这也将消除声纳发出的警告。请参见https://projectlombok.org/features/EqualsAndHashCode –这还向您展示了如何使用canEqual
概念来避免ColoredArrayList困境。
在这里您无需添加新属性就可以创建子类,因此,实际上不需要替换hashCode和equals。但是声纳不知道。
答案 1 :(得分:0)
在子类中重写equals()和hashcode()方法将有效 考虑孩子的班级成员(变量),这也有助于 使用Collection框架的子类型和Map实例来查找 收集框架操作期间的正确内存空间(存储桶)(例如: 保存/检索)。
在这里继承超类可能会错过子类成员 有效地生成哈希码/等于方法的功能。
答案 2 :(得分:0)
在实现中,您可以有两个{em}相等的Parent
引用,但它们指向两个不同类的对象,因此可以将其强制转换为Child
并另一个-不。
这是非常出乎意料的,并且可能会导致问题发展-Sonar的工作就是指出这一点。如果您认为这对于您的用例是合理的,则只需在Sonar的警告下将其记录下来即可(这是我会做的)。