【问题标题】:Can I change the inner structure of objects in a HashTable while iterating over it?我可以在迭代 HashTable 时更改对象的内部结构吗?
【发布时间】:2015-11-01 14:37:19
【问题描述】:

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

如果这个问题已经回答了很多次,我们深表歉意。

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

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

【问题讨论】:

    标签: java collections foreach concurrency hashmap


    【解决方案1】:

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

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

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

    不,这是不可能的。为了用另一个密钥替换容器中的密钥,您需要先删除该项目,然后用新密钥重新插入它。但是,这会触发并发修改异常。

    如果您需要替换大量的键,最好的方法是制作一个新的哈希容器,并在迭代原始容器时使用键值对填充它。

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

    【讨论】:

    • "不,这是不可能的。为了用另一个密钥替换容器中的密钥,您需要先删除该项目,然后用新密钥重新插入它。这个,但是,会触发并发修改异常。”嗯什么?您可以遍历 entrySet() 并在条目上调用 setValue
    • 这听起来不像 OP 在该行中所说的那样。它在谈论“替换键的值”,这正是 setValue 所做的,不是吗?
    • @LouisWasserman OP 的method2 的第 2 行和第 3 行显示了他想要做的事情:迭代 keySet(),并更改各个键的内部状态。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-09
    • 2019-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多