如何获取和更改哈希图的值,而不更改 Java 中的哈希图本身?

How to get and change a value of a hashmap, without changing the hashmap itself in Java?

我有一个HashMap如下,

Map<String, MyClass> testMap = new HashMap<>();
map.put("1", myClass1);
map.put("2", myClass2);

这里MyClass是一个beanclass。现在我希望获得 testMap 的值,并在不更改 testMap 本身的情况下更改该值。我的做法如下,

MyClass result = testMap.get("1");
if (some conditions){
    do someting to result;
}
return result;

我期望的是result改变而testMap保持不变。但实际上 testMap 中的 myClass1 也发生了变化。那么我怎样才能实现我的目标呢?

有多种方法可以实现:

  1. 当您从 testMap 中取出一个对象时,您首先要手动将其复制到相同类型的新对象中。在 C++ 中,这通常使用复制构造函数实现:new MyClass1(myClass); 其中复制构造函数获取传入对象的所有字段并将其复制到新对象中,在 Java 中,有时使用 Cloneable 接口.
  2. 使您的对象不可变,这样对象上的更改永远不会改变其状态,但总是 returns 包含这些更改的新对象。一个相对较新的示例是 BigDecimal,其中对 BigDecimal 对象的每个操作总是 returns 一个新的 BigDecimal 对象。

可以通过创建不可变对象来实现。当您更改此对象的值时,它总是会创建一个新对象并且不会更改原始值。

MyClass 的不可变实现:

public class MyClass {
    private final String name;

    public MyClass(String name) {
        this.name = name;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

}

验证不变性的客户端:

import java.util.HashMap;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        MyClass myClass = new MyClass("class1");
        System.out.println("Object " + myClass);

        Map<Integer, MyClass> map = new HashMap<Integer, MyClass>();
        map.put(1, myClass);

        MyClass result = map.get(1);
        System.out.println("From Map Object " + result);
        String name = result.getName();
        if (name != null && name.equals("class1")) {
            MyClass updatedResult = new MyClass("updatedclass1 ");
            System.out.println("Updated Object " + updatedResult);
        }
        System.out.println("From Map Object " + result);

    }
}

输出:

Object MyClass@6d06d69c
From Map Object MyClass@6d06d69c
Updated Object MyClass@7852e922
From Map Object MyClass@6d06d69c

更新地图后保持原样。

您需要复制 MyClass。 如果您对其中的对象有引用,则需要深拷贝。

在地图中,它存储对对象的引用。因此,当您从映射中获取对该对象的引用并对其进行修改时,您正在修改该对象的同一实例。如果您制作副本,您将能够对其中一个进行更改,但不能对另一个进行更改。

浅拷贝与深拷贝

浅拷贝可以用.clone()来完成,只是拷贝所有字段,如果class中有对象作为字段,只引用将被复制。这是有问题的,因为您将在每个副本中拥有相同的内部对象副本,并且最终会遇到与上述相同的情况 - 当您修改其中任何一个对象时,您也会修改其他对象。

深度复制缓解了这个问题,因为它也复制了内部对象。 您可以遍历并递归复制,通过序列化或外部库(如 Apache Commons Lang SerializationUtils.clone())进行复制。如果您好奇的话,这个 link 有更多的细节。 https://www.baeldung.com/java-deep-copy