【问题标题】:How to set the key-value pairs of a HashMap final in Java 11?如何在 Java 11 中设置 HashMap final 的键值对?
【发布时间】:2020-04-11 19:43:35
【问题描述】:
import java.util.HashMap;
import java.util.Map;

public class Foo {
    private final Map<String, Integer> exits;

    public Foo() {
        this.exits = new HashMap<>();
    }

    public Map<String, Integer> getExits() {
        return exits;
    }

    public void show() {
        for (String i : exits.keySet()) {
            System.out.println(i + ": " + exits.get(i));
        }
    }
}

class Bar {
    public static void main(String[] args) {
        Foo foo = new Foo();
        foo.getExits().put("A", 1);
        foo.getExits().put("B", 2);
        foo.show();
        //Okay, no problem.
        //Output: A: 1
        //        B: 2
        foo.getExits().replace("A", 10);
        foo.getExits().remove("B");
        foo.show();
        //Output: A: 10
    }
}

我已经在Foo 类中将exits 声明为final,这样一旦在构造函数中分配了它就不能引用另一个HashMap。我还想将exits 中的每个元素都设置为final,这样一旦我在exits 中放置了一个键值对,就不能以任何方式修改或删除它。我尝试了以下方法(注意getExits()方法和main()方法的变化):

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

public class Foo {
    private final Map<String, Integer> exits;

    public Foo(Map<String, Integer> exits) {
        this.exits = exits;
    }

    public Map<String, Integer> getExits() {
        return new HashMap<>(exits);
    }

    public void show() {
        for (String i : exits.keySet()) {
            System.out.println(i + ": " + exits.get(i));
        }
    }
}

class Bar {
    public static void main(String[] args) {
        Map<String, Integer> temp=new HashMap<>();
        temp.put("A", 1);
        temp.put("B", 2);
        Foo foo = new Foo(temp);

        foo.show();
        //Okay, no problem.
        //Output: A: 1
        //        B: 2
        foo.getExits().replace("A", 10);
        foo.getExits().remove("B");
        foo.show();
        //Output: A: 1
        //        B: 2
    }
}

问题 1:
如果我将exits 声明为private final Map&lt;final String, final Integer&gt; exits;,为什么它不起作用?
问题2:
有没有其他方法可以达到同样的效果?

P.S:我是Java新手,如果有任何错误请纠正我,因为我可能将C++概念与Java混合在一起。

【问题讨论】:

  • 你想要 Collections.unmodifiableMap() 或者像 Guava 的 ImmutableMap 这样的不可变版本。
  • @chrylis-onstrike- 你能详细解释一下吗?
  • 了解 Collections.unmodifiableMap here
  • Final 只是使参考成为最终的,因此您不能将其指向新地图。它与使数据不可变的 c 的 const 不同。您可以通过创建您的类不公开的重复 Map 来实现您所追求的目标。例如。当您调用 getExits 时,您会返回一个 unmodifiableMap (这只是您现有地图的视图)。编辑:就像你的额外例子一样。
  • 或 Java 12 的 Map.copyOf()

标签: java hashmap final java-11


【解决方案1】:

答案 1:Map&lt;final String, final Integer&gt; 在 Java 中不是有效的语法。我不知道你的意思是什么。这个用法让我想起了 C++ 中的 const 修饰符,但是 final 不是 const,而且无论如何 String 和 Integer 已经是不可变的了

答案 2:您的 getExits 方法返回地图的可修改副本。这可行,但更常见的是返回数据结构的不可修改视图。它是一个轻量级装饰器,如果调用者尝试进行更改,则会引发异常,否则会调用原始映射中的方法。如果需要,调用者必须自己复制地图。

public Map<String, Integer> getExits() {
    return Collections.unmodifiableMap(exits);
}

【讨论】:

    【解决方案2】:

    第一个问题: 实际上,在第二个代码中,当您每次调用 getexits 时,它都会返回一个不同的浅拷贝(新 Hashmap)。浅拷贝是退出的不同副本,您只能修改返回的映射,而不是您在 foo 类中声明的原始映射。所以,foo.getexits() 是你返回的完全不同的映射,它每次都在修改新的哈希映射,而不是临时的或者 foo(temp)。如果你这样编码,

        temp.replace("A",10);
        temp.remove("B");
        foo.show(); 
    

    而不是,

        foo.getExits().replace("A", 10);
        foo.getExits().remove("B");
        foo.show();
    

    然后它将打印与您的第一个程序相同的输出。(它也会修改)。 很快,您的第二个代码不会修改,因为每次您返回和修改与 temp.so 无关的新哈希图时,这些都不会影响您的 foo(temp)。

    第二个问题: 如果您真的不想修改主类中的任何内容,那么您可以在第二个程序的 getexits() 方法中编写如下代码:

      return Collections.unmodifiableMap(exits);
    

    不要像你一样改变第二个程序的任何内容。然后它会抛出

     java.lang.UnsupportedOperationException
    

    每当您想使用 foo.getexits() 进行修改并阻止您对其进行修改时。但您仍然可以单独修改 temp,因为它与 getexits 方法无关。我也是像您一样的初学者,但我已经尝试过用我的小知识回答你的问题。希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-30
      • 1970-01-01
      • 2010-11-25
      相关资源
      最近更新 更多