gpt4 book ai didi

Java 更改类的一个实例的属性也会更改另一个实例

转载 作者:行者123 更新时间:2023-12-02 02:00:36 25 4
gpt4 key购买 nike

总结问题:子类的不同实例是否继承同一个父类实例?

我本以为子类的两个实例也有不同的父类实例,但也许我不了解继承的一些内容。希望有人能解释为什么我会看到这种行为。

这是我看到“问题”的类(class):

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

当我在 FastenersCapScrew 中调用 getFilters() 方法时,lengththreadLength 的初始输出为正如预期的那样,两者都有 dbColumnName=null。然后它运行 length.setDbColumnName("FK_LengthID");,但是两者 lengththreadLength 都发生了更改,并且两者显示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 实例也会更改另一个实例吗?解决这个问题的方法是什么,以便我确实拥有两个完全独立的实例?谢谢!

就其值(value)而言,我正在使用 Java 8 和 Spring Boot 2.0.3 以及 Hibernate,但我认为这与这个问题没有任何关系。

最佳答案

子类的两个实例肯定不会共享其父字段的内存。也许造成这种行为的原因只是 Hibernate 的缓存。 Hibernate 确实为 FastenerCapScrew 类的字段之一创建了一个新的 Dimension 实例,而是从缓存中加载它。尝试启用 SQL 查询日志记录以调查调用 getFilters 方法时发生的情况。

编辑获取本质上相同实体的不同实例的最简单方法是在 setter 中使用防御性复制。只要您不将此技术应用于集合,Hibernate 仍然应该能够执行脏检查,因为它按值比较对象。相反,集合是通过身份进行比较的,脏检查对它们不起作用。

关于Java 更改类的一个实例的属性也会更改另一个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51643552/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com