如何解决StackOverflow 错误 - 带有 HashMap <Entity,Integer> 的 JPA 实体
我想做一个小生产计算器。我有一个需要 7 秒的 A 部分,它由需要 3 秒的 x 部分 B 和需要 2 秒的 y 部分 C 组成。 C 部分由 n 个 D 部分组成。 所以我在 Class Part 中有一个递归,它的使用次数是“配方”。 我的实体类
@Entity
@Data
public class ProductEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique=true)
private String name;
private double productionCycleTimeInSeconds;
private int batchPerProductionCycle;
@Enumerated(EnumType.ORDINAL)
private FacilityEnum facility;
@ElementCollection
@JoinTable(name = "end_product_recipe",joinColumns = @JoinColumn(name = "end_product_id"))
@MapKeyColumn(name = "resourceId")
@Column(name = "usage_count")
private Map<ProductEntity,Integer> recipe;
}
为了测试,我想用 3 个基础来初始化表
ProductEntity ironore = new ProductEntity();
ironore.setFacility(FacilityEnum.MINING_MACHINE);
ironore.setName("Iron Ore");
ironore.setProductionCycleTimeInSeconds(1.0);
ironore.setBatchPerProductionCycle(1);
productRepository.save(ironore);
ProductEntity ironIngot = new ProductEntity();
ironIngot.setFacility(FacilityEnum.SMELTER);
ironIngot.setName("Iron Ingot");
ironIngot.setProductionCycleTimeInSeconds(1.0);
ironIngot.setBatchPerProductionCycle(1);
Map<ProductEntity,Integer> recipe = new HashMap<>();
recipe.put(ironore,1);
ironIngot.setRecipe(recipe);
productRepository.save(ironIngot);
ProductEntity gear = new ProductEntity();
gear.setFacility(FacilityEnum.ASSEMBLING_MACHINE);
gear.setName("Gear");
gear.setProductionCycleTimeInSeconds(1.0);
gear.setBatchPerProductionCycle(1);
recipe.clear();
recipe.put(ironIngot,1);
gear.setRecipe(recipe);
productRepository.save(gear);
当代码到达最后一行时 (productRepository.save(gear);) 我得到错误:
java.lang.StackOverflowError
at java.util.HashMap$HashIterator.<init>(HashMap.java:1427)
at java.util.HashMap$EntryIterator.<init>(HashMap.java:1477)
at java.util.HashMap$EntrySet.iterator(HashMap.java:1014)
at java.util.AbstractMap.hashCode(AbstractMap.java:528)
at org.hibernate.collection.internal.PersistentMap.hashCode(PersistentMap.java:574)
at com.hoernerice.dspcalculator.entity.ProductEntity.hashCode(ProductEntity.java:12)
at java.util.Objects.hashCode(Objects.java:98)
at java.util.HashMap$Node.hashCode(HashMap.java:297)
at java.util.AbstractMap.hashCode(AbstractMap.java:530)
at org.hibernate.collection.internal.PersistentMap.hashCode(PersistentMap.java:574)
at com.hoernerice.dspcalculator.entity.ProductEntity.hashCode(ProductEntity.java:12)
at java.util.Objects.hashCode(Objects.java:98)
at java.util.HashMap$Node.hashCode(HashMap.java:297)
at java.util.AbstractMap.hashCode(AbstractMap.java:530)
at org.hibernate.collection.internal.PersistentMap.hashCode(PersistentMap.java:574)
at com.hoernerice.dspcalculator.entity.ProductEntity.hashCode(ProductEntity.java:12)
at java.util.Objects.hashCode(Objects.java:98)
at java.util.HashMap$Node.hashCode(HashMap.java:297)
at java.util.AbstractMap.hashCode(AbstractMap.java:530)
at org.hibernate.collection.internal.PersistentMap.hashCode(PersistentMap.java:574)
at com.hoernerice.dspcalculator.entity.ProductEntity.hashCode(ProductEntity.java:12)
....
它重复,所以我想我有一个无限循环。但是怎么样?我的错误在哪里?对于前 2 个项目,我将行作为数据库中接受的行。在连接表中是“只是”想要的 ID。这样工作就被接受了
通过替换解决
recipe.clear()
与
recipe = new HashMap<>();
解决方法
HashMap.hashCode()
负责溢出。
HashMap
从 AbstractMap
扩展,在他的 hashCode()
方法中,对每个条目的哈希码求和:
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
为什么是无限递归循环?
ironIngot.setRecipe(recipe);
以及以下内容
recipe.put(ironIngot,1);
使 HashMap
成为其自身的条目。因此,当它调用 hashCode()
时,它会在计算其条目的哈希码时再次调用他的哈希码方法:next().hashCode()
。一次又一次……无限循环。
溢出循环的简化
MapX
+--------------+
/| /|
/ | / |
*--+-----------* |
| | | |
| |- [MapX]------|-- ----
| | | | |
| +-----------+--+ |
| / | / |
|/ |/ |
*--------------* |
MapX V
+--------------+
/| /|
*-+------------* |
| | | |
| |- [MapX]----|-|---------
| | | | |
| +------------+-+ |
|/ |/ |
*--------------* |
MapX V
+--------------+
/| /|
*-+------------* |
| | | |
| |- [MapX]--------------
| | | | |
| +------------+-+ |
|/ |/ |
*--------------* V
(Road to Overflow Town)
正如您所评论的,创建新的 HashMap
避免了这种情况,因为现在没有地图将自身作为其条目之一包含在内,您破坏了引用链。
解释这种行为的代码是这个,本质上和你的一样:
Map<Object,String> map = new HashMap<>();
map.put(map,"letsLooop");
map.hashCode();
此代码段还会导致 stackoverflow
错误,这是由于 AbstractMap
的 hashCode()
实现中的无限循环,它将在死锁循环中调用其自己的 hashCode 方法结果是一个漂亮的StackOverflow
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。