StackOverflow 错误 - 带有 HashMap 的 JPA 实体 <Entity,Integer>
StackOverflow Error - JPA Entity with HashMap <Entity,Integer>
我想做一个小量产计算器。我有一个需要 7 秒的 A 部分,它由需要 3 秒的 x 部分 B 和需要 2 秒的 y 部分 C 组成。 C 部分由 n 个 D 部分组成。
所以我在 Class 部分有一个递归,它的使用次数作为“配方”。
我的实体 Class
@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 个基础知识初始化 table
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.WhosebugError
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 个项目,我有数据库中接受的行。在加入 table 中是“只是”想要的 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();
由于 AbstractMap
的 hashCode()
实现中的无限循环,此代码段也会导致 Whosebug
错误,它将在死锁中调用自己的 hashCode 方法产生美丽 Whosebug
.
的循环
我想做一个小量产计算器。我有一个需要 7 秒的 A 部分,它由需要 3 秒的 x 部分 B 和需要 2 秒的 y 部分 C 组成。 C 部分由 n 个 D 部分组成。 所以我在 Class 部分有一个递归,它的使用次数作为“配方”。 我的实体 Class
@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 个基础知识初始化 table
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.WhosebugError
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 个项目,我有数据库中接受的行。在加入 table 中是“只是”想要的 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();
由于 AbstractMap
的 hashCode()
实现中的无限循环,此代码段也会导致 Whosebug
错误,它将在死锁中调用自己的 hashCode 方法产生美丽 Whosebug
.