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;
}