如何在Java 11中设置HashMap final的键-值对?

问题描述 投票:-1回答:2
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
    }
}

我在exits类中将Foo声明为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<final String, final Integer> exits;,为什么它不起作用?问题2:还有其他方法可以实现相同目标吗?附注:我是Java新手,所以如果有任何错误,请更正我,因为我可能将C ++概念与Java混在一起。

java hashmap final java-11
2个回答
1
投票

答案1:Map<final String, final Integer>在Java中不是有效的语法。我不知道你是什么意思。这种用法使我想起了C ++中的const修饰符,但final不是const,并且在任何情况下String和Integer都是不可变的

答案2:您的getExits方法返回地图的可修改副本。可以,但是返回数据结构的unmodifiable view更为常见。它是一个轻量级的装饰器,如果调用者尝试进行更改,则抛出异常,但否则将调用原始映射中的方法。如果需要,调用者必须复制地图本身。

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

1
投票

第一个问题:实际上在第二个代码中,当您每次调用getexits时,都会返回一个不同的浅表副本(新的Hashmap)。shallowcopy是退出表的另一副本,您只能修改返回的映射,而不能修改在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方法没有关系。我也是您的初学者,但是我已经尝试过用我的小知识回答您的问题。希望会有所帮助

© www.soinside.com 2019 - 2024. All rights reserved.