java - 使用 hashmap 的不可变类示例

标签 java immutability

我定义了以下类,试图使“IamImmutable.class”不可变。但是当我在初始化 IamImmutable 后更改 TestingImmutability.class 中的 hashmap 值时,更改适用于 Hashmap。即使我们用 new HashMap(old) 实例化它,Hashmap 也会引用同一个对象。我需要使实例中的 Hashmap 不可变。我也尝试过迭代和复制值,但这不起作用。谁能建议如何进行?

package string;
import java.util.HashMap;
import java.util.Map.Entry;

public final class IamImmutable {
  private int i;
  private String s;
  private HashMap<String, String> h;

  public IamImmutable(int i, String s, HashMap<String, String> h) {
    this.i = i;
    this.s = s;

    this.h = new HashMap<String, String>();
    for (Entry<String, String> entry: h.entrySet()) {
      this.h.put((entry.getKey()), entry.getValue());
    }
  }

  public int getI() {
    return i;
  }

  public String getS() {
    return s;
  }

  public HashMap<String, String> getH() {
    return h;
  }
}

还有一个测试:

package string;

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

public class TestingImmutability {

  public static void main(String[] args) {
    int i = 6;
    String s = "!am@John";
    HashMap<String, String> h = new HashMap<String, String>();

    h.put("Info1", "!am@John");
    h.put("Inf02", "!amCrazy6");


    IamImmutable imm = new IamImmutable(i, s, h);

    h.put("Inf02", "!amCraxy7");

    System.out.println(imm.getS() + imm.getI());
    for (Entry<String, String> entry: h.entrySet())
      System.out.println(entry.getKey() + " --- " + entry.getValue());
  }
}

Expected output:

  !am@ John6
Inf02---!amCrazy6
Info1---!am@ John

Actual output:

  !am@ John6
Inf02---!amCraxy7
Info1---!am@ John

最佳答案

你的测试是错误的,你正在检查 h 的内容,你传递给构造函数并随后修改的映射,而不是 imm.getH() .如果你检查正确的 map

for (Entry<String, String> entry : imm.getH().entrySet())
        System.out.println(entry.getKey() + " --- " + entry.getValue());

一切看起来都很好:

!am@John6
Info1 --- !am@John
Inf02 --- !amCrazy6

所以您的 IamImmutable 构造函数已经很好,以后对传递给构造函数的原始映射的任何更改都不会影响您在构造时创建的副本。您还可以使用 other HashMap constructor你提到过,它的可读性稍强一些:

public IamImmutable(int i, String s, HashMap<String, String> h)
{
    this.i = i;
    this.s = s;
    this.h = new HashMap<String, String>(h);
}

这也能正常工作。


另一个问题是 getH() 将内部 map 的引用传递给世界,如果世界更改该引用,事情就会出错。一个简单的解决方法是应用您已经在 getH() 的构造函数中使用的相同复制技巧:

public HashMap < String, String > getH() {
    return new HashMap<String,String>(h);
}

或者在返回之前装饰内部 map :

public Map<String, String> getH() {
    return Collections.unmodifiableMap(h);
}

考虑使用 ImmutableCollections in the guava library反而。他们完成了与此代码相同的工作,但更多地考虑了效率和易用性。构造时的完整副本和获取 map 的操作很笨重,如果我们知道它无论如何都不会被修改,那么标准的底层 HashMap 将进行毫无意义的修改检查。

关于java - 使用 hashmap 的不可变类示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29740709/

相关文章:

java - Hibernate:如何使用 Criteria Interface 检索最后 N 个条目?

java - 为什么RecyclerView没有显示任何项目?

java - 在类路径中找不到驱动程序。

python - 不可变对象(immutable对象)的内存分配

javascript - 如何实现不变性

java - startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION) 上出现 NullPointException;

java - 在每个单元测试后创建一个新的 bean 实例

scala - 条件变量设置

java - 如何在 Guava 中制作一个 "real"不可变的日期对象列表

c# - C++ 字符串与 C# 字符串,不同的运行时间。为什么?