在迭代它时,我可以更改HashTable中对象的内部结构吗?

时间:2015-08-09 17:09:33

标签: java collections foreach concurrency hashmap

就像标题所说的那样。在迭代其键时,我可以更改HashTable中对象的内部结构吗?我知道我不能改变地图本身,或者至少这样做有风险,但是尽管谷歌搜索我还没有找到任何明确或简单的答案,是否可以改变对象本身的属性在hashmap中。我的直觉不是,因为这可能会改变哈希,但是肯定知道肯定会很好。我也有兴趣在迭代它们时替换键的值。这可能吗?

道歉,如果之前已经回答了很多次。

简而言之,这两种方法是否会按预期工作?

public class Manager {

private Hashtable<MyClassA, BufferedImage> ht1;
private Hashtable<MyClassB, JSlider> ht2;

private Image method1() {
    for(MyClassB mcb: ht2.keySet()){
       mcb.calculateStuff(ht2.get(mcb).getValue());
       //CalculateStuff() doesnt change anything, but if it takes long, the JSliders might be
       //changed by the user or a timer, resulting in a new hashCode(), and potentially problems.
    }
}

private void method2(){
   for(MyClassA mca: ht1.keySet()){
       mca.changeInnerStructureOfA(); //Changes the fields of the object mca.
       ht1.put(mca.calculateNewImage());
   }
}

1 个答案:

答案 0 :(得分:2)

不允许在任何情况下改变基于散列的容器的键,而不仅仅是在迭代容器时。这样做的原因是,当散列键位于与键的散列值不对应的散列桶中时,任何更改散列函数值的突变都会使容器处于无效状态。

这是强烈建议仅使用不可变类作为基于散列的容器中的键的原因。

  

我也有兴趣在迭代它们时替换键的值。这可能吗?

不,这是不可能的。要使用其他键替换容器中的键,您需要先删除该项,然后使用新键重新插入。但是,这会触发并发修改异常。

如果您需要替换大量的密钥,最好的方法是创建一个新的哈希容器,并在迭代原始容器时用key-vale对填充它。

如果您只需要替换少量密钥,请创建描述更改的对象列表(旧密钥,新密钥,值),在迭代原始容器时填充列表,然后遍历更改列表对原始容器进行更改。