摘要问题:子类的不同实例是否继承相同的父类实例?
我本以为子类的两个实例也具有不同的父类实例,但是也许我对继承没有了解。希望有人可以解释为什么我会看到这种行为。
这是我看到“问题”的班级:
@Entity
@Table(name="inventory.parts_fstnr_capscrews")
public class FastenerCapScrew implements PartInterface {
...
private Dimension length;
private Dimension threadLength;
...
@ManyToOne
@JoinColumn(name="fk_lengthid")
@JsonView(View.CommodityPartPOView.class)
public Dimension getLength() {
return length;
}
public void setLength(Dimension length) {
this.length = length;
}
@ManyToOne
@JoinColumn(name="fk_threadlengthid")
@JsonView(View.CommodityPartPOView.class)
public Dimension getThreadLength() {
return threadLength;
}
public void setThreadLength(Dimension threadLength) {
this.threadLength = threadLength;
}
@Override
@Transient
public List<FiltersInterface> getFilters() {
List<FiltersInterface> filters = new ArrayList<>();
LOGGER.debug(filters.toString());
LOGGER.debug(length.toString());
LOGGER.debug(threadLength.toString());
if (length!=null) {
length.setDbColumnName("FK_LengthID");
filters.add(length);
}
LOGGER.debug(filters.toString());
LOGGER.debug(length.toString());
LOGGER.debug(threadLength.toString());
if (threadLength!=null) {
threadLength.setDbColumnName("FK_ThreadLengthID");
filters.add(threadLength);
}
LOGGER.debug(filters.toString());
LOGGER.debug(length.toString());
LOGGER.debug(threadLength.toString());
return filters;
}
}
这是Dimension类:
@Entity
@Table(name="utilities.dimensions")
public class Dimension extends FiltersExtension implements FiltersDimensionInterface {
...
}
扩展类:
public class FiltersExtension {
protected String dbColumnName;
public String getDbColumnName() {
return dbColumnName;
}
public void setDbColumnName(String dbColumnName) {
this.dbColumnName = dbColumnName;
}
}
当我在getFilters()
中调用FastenersCapScrew
方法时,length
和threadLength
的初始输出是预期的,并且都具有dbColumnName=null
。然后它运行length.setDbColumnName("FK_LengthID");
,但是两者 length
和threadLength
都被更改,并且都显示dbColumnName=FK_LengthID
。然后运行threadLength.setDbColumnName("FK_ThreadLengthID");
,并再次更改两个项目,以使dbColumnName=FK_ThreadLengthID
。
最初,我认为它必须与Dimension
中的hashCode和equals方法有关,因此我将它们更改为包括dbColumnName
,如下所示:
@Override
public int hashCode() {
LOGGER.debug("First compare hashCode with dbColumnName="+this.dbColumnName);
int hash = 3;
hash = 37 * hash + this.dimID;
hash = 37 * hash + Objects.hashCode(this.dbColumnName);
return hash;
}
@Override
public boolean equals(Object obj) {
LOGGER.debug("Now compare equals with dbColumnName="+this.dbColumnName);
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Dimension other = (Dimension) obj;
if (this.dimID != other.dimID) {
return false;
}
LOGGER.debug("Now compare the column name: "+this.dbColumnName+" vs. "+other.dbColumnName);
if (!Objects.equals(this.dbColumnName,other.dbColumnName)) {
return false;
}
return true;
}
有人可以向我解释为什么更改一个Dimension
实例也会同时更改另一个实例吗?为了解决这个问题,使我确实拥有两个完全独立的实例,该怎么办?谢谢!
对于它的价值,我将Java 8和Spring Boot 2.0.3与Hibernate一起使用,但是我认为这与该问题没有任何关系。
答案 0 :(得分:2)
肯定有两个子类实例不共享其父字段的内存。也许导致这种现象的原因仅仅是Hibernate的缓存。 Hibernate确实为Dimension
类的一个字段创建了FastenerCapScrew
的新实例,而不是从缓存中加载它。尝试启用SQL查询日志记录,以调查调用getFilters
方法时发生的情况。
编辑 获取基本相同实体的不同实例的最简单方法是在setter中使用防御性复制。只要您不将此技术应用于集合,Hibernate仍应能够执行脏检查,因为它按值比较对象。相比之下,收集是通过身份进行比较的,脏检查对它们不起作用。