Java更改类的一个实例的属性也会更改另一个实例
摘要问题:子类的不同实例是否继承同一父类实例? 我本以为一个子类的两个实例也有不同的父类实例,但也许我不了解继承的某些方面。希望有人能解释为什么我会看到这种行为 这是我看到“问题”的课堂: 和扩展类:Java更改类的一个实例的属性也会更改另一个实例,java,inheritance,Java,Inheritance,摘要问题:子类的不同实例是否继承同一父类实例? 我本以为一个子类的两个实例也有不同的父类实例,但也许我不了解继承的某些方面。希望有人能解释为什么我会看到这种行为 这是我看到“问题”的课堂: 和扩展类: public class FiltersExtension { protected String dbColumnName; public String getDbColumnName() { return dbColumnName; } pub
public class FiltersExtension {
protected String dbColumnName;
public String getDbColumnName() {
return dbColumnName;
}
public void setDbColumnName(String dbColumnName) {
this.dbColumnName = dbColumnName;
}
}
当我在FastenersCapScrew
中调用getFilters()
方法时,length
和threadLength
的初始输出与预期一致,并且两者都具有dbColumnName=null
。然后运行length.setDbColumnName(“FK_LengthID”)
,但两个长度和螺纹长度都已更改,并且都显示dbColumnName=FK_LengthID
。然后运行threadLength.setDbColumnName(“FK_ThreadLengthID”)
和这两个项都会更改,以便dbColumnName=FK_ThreadLengthID
起初,我认为它一定与维度中的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;
}
有人能解释一下为什么更改一个维度实例也会更改另一个维度吗?怎样才能解决这个问题,这样我就有了两个完全不同的实例?谢谢
值得一提的是,我在Hibernate中使用Java 8和Spring Boot 2.0.3,但我认为这与这个问题没有任何关系。毫无疑问,一个子类的两个实例不共享其父字段的内存。可能这种行为的原因只是Hibernate的缓存。Hibernate确实为FastenerCapScrew
类的一个字段创建了Dimension
的新实例,而不是从缓存加载它。尝试启用SQL查询日志记录,以调查调用getFilters
方法时发生的情况
编辑
获取本质上相同实体的不同实例的最简单方法是在setter中使用防御性复制。只要不将此技术应用于集合,Hibernate应该仍然能够执行脏检查,因为它会按值比较对象。相反,集合是通过标识进行比较的,脏检查对它们不起作用。一个子类的两个实例肯定不会共享其父字段的内存。可能这种行为的原因只是Hibernate的缓存。Hibernate确实为FastenerCapScrew
类的一个字段创建了Dimension
的新实例,而不是从缓存加载它。尝试启用SQL查询日志记录,以调查调用getFilters
方法时发生的情况
编辑
获取本质上相同实体的不同实例的最简单方法是在setter中使用防御性复制。只要不将此技术应用于集合,Hibernate应该仍然能够执行脏检查,因为它会按值比较对象。相反,集合是通过标识进行比较的,脏检查对它们不起作用。您在哪里初始化那些维度对象,即如何调用setLength()
和setThreadLength()
?@Mick助记符维度
对象作为Spring数据JPA/Hibernate的一部分进行初始化。因此,对于给定的FastenerCapScrew
数据库记录,它会找到相应的维度
数据库记录并构建对象。您在哪里初始化这些维度
对象,即如何调用setLength()
和setThreadLength()
?@Mick助记符维度
对象作为Spring数据JPA/Hibernate的一部分进行初始化。因此,对于给定的FastenerCapScrew
数据库记录,它会找到相应的维度
数据库记录并构建对象。感谢您的反馈。这似乎与你的建议是一致的。在我注意到这种行为的情况下,length
和threadLength
恰好是相同的。在这种情况下,我在日志中只看到一个构建维度对象的位置。如果使用length
和threadLength
不同的情况,那么日志将显示正在构建的二维对象。那么,我如何强制它使用两个不同的对象,即使最初的值是相同的呢?太棒了。我从来没有听说过防御性抄袭。谢谢谢谢你的反馈。这似乎与你的建议是一致的。在我注意到这种行为的情况下,length
和threadLength
恰好是相同的。在这种情况下,我在日志中只看到一个构建维度对象的位置。如果使用length
和threadLength
不同的情况,那么日志将显示正在构建的二维对象。那么,我如何强制它使用两个不同的对象,即使最初的值是相同的呢?太棒了。我从来没有听说过防御性抄袭。谢谢
public class FiltersExtension {
protected String dbColumnName;
public String getDbColumnName() {
return dbColumnName;
}
public void setDbColumnName(String dbColumnName) {
this.dbColumnName = 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;
}