在 Java 中,我可以声明一个 HashMap 常量吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43906226/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:12:33  来源:igfitidea点击:

In Java, can I declare a HashMap constant?

javahashmapconstants

提问by Hoonta

I am writing a simple program to convert a number to a word representing that number (13 => "thirteen").

我正在编写一个简单的程序来将一个数字转换为代表该数字的单词(13 =>“十三”)。

I realize I could get some of the words with a constant String array like this:

我意识到我可以使用这样的常量字符串数组来获取一些单词:

private static final String[] tensNames = {"", " ten", " twenty", " thirty", " forty", " fifty", " sixty", " seventy", " eighty", " ninety" };

...and access it with the index, but I wanted to try it with a HashMap like this:

...并使用索引访问它,但我想用这样的 HashMap 尝试它:

final HashMap<Integer, String> tensNumberConversion = new HashMap<Integer, String>();
    tensNumberConversion.put(2, "twenty");
    tensNumberConversion.put(3, "thirty");
    tensNumberConversion.put(4, "forty");
    tensNumberConversion.put(5, "fifty");
    tensNumberConversion.put(6, "sixty");
    tensNumberConversion.put(7, "seventy");
    tensNumberConversion.put(8, "eighty");
    tensNumberConversion.put(9, "ninety");

I was instructed by a teacher to make these constants. Can the HashMap be a constant? As a newbie, it wasn't totally clear how the terms "constant" and "static" and "final" are related, and what exactly makes a constant. (static alone? final alone? static final together?).

一位老师指示我制作这些常数。HashMap 可以是常量吗?作为新手,并不完全清楚术语“常量”、“静态”和“最终”是如何相关的,以及究竟是什么构成了常量。(单独静态?单独final?一起静态final?)。

I tried making it private static final Hashmap but IntelliJ gave me an error (modifier 'private' not allowed here...same for 'static').

我尝试将其设为私有静态最终 Hashmap,但 IntelliJ 给了我一个错误(此处不允许使用修饰符 'private'...'static' 也是如此)。

However, it does compile from my terminal with no errors. If a HashMap can be a constant, is this the right way to declare one? Thanks!

但是,它确实从我的终端编译没有错误。如果 HashMap 可以是一个常量,这是声明一个的正确方法吗?谢谢!

采纳答案by GhostCat

There are two aspects here:

这里有两个方面:

  • You have a variable that holds a reference to a map. You simply declare that variable to be final; and voilà, you can't change the variable to point to anotherreference.
  • But that doesn't prevent you from changing the stateof the object that reference is pointing. So even when you have a final Mapobject, you could still call put/remove/... methods on that Map.
  • 您有一个保存对地图的引用的变量。您只需将该变量声明为final;瞧,您不能将变量更改为指向另一个引用。
  • 但这并不能阻止您更改引用指向的对象的状态。所以即使你有一个最终的 Map对象,你仍然可以在那个 Map 上调用 put/remove/... 方法。

So, in order to come to a real "constant" Map, you do go for this:

所以,为了得到一个真正的“恒定”地图,你一定要这样做:

First you create an ordinary map containing all the desired values.

首先,您创建一个包含所有所需值的普通地图。

Then you use Collections.unmodifiableMap()in order to create a map that can't be changed any more.

然后您使用Collections.unmodifiableMap()为了创建不能再更改的地图。

The one thing to pay attention to: you have to make sure that you are not leaking a reference to the original map object as that immutable map is just a wrapper around that initial map. You could do that in a little helper method for example.

需要注意的一件事是:您必须确保不会泄漏对原始地图对象的引用,因为该不可变地图只是该初始地图的包装器。例如,您可以在一个小助手方法中做到这一点。

If you are asking: is there a way to write down a map declaration in a special "literal form" (like for arrays) - there isn't. Well, you can change that helper method to take Object ...as parameter; and then you would go through those parameters, one is a number, next one a string, and use that to fill the map. So you could then invoke the method with a single sequence of values. But probably not worth the effort ...

如果您问:有没有办法以特殊的“文字形式”(如数组)写下地图声明 - 没有。好吧,您可以更改该辅助方法以Object ...作为参数;然后你会检查这些参数,一个是数字,下一个是字符串,然后用它来填充地图。因此,您可以使用单个值序列调用该方法。但可能不值得努力......

A quick update: Java9 added various static helper methods that allow you write down maps in a somehow "literal" way, see herefor example.

快速更新:Java9 添加了各种静态辅助方法,允许您以某种“文字”方式写下地图,例如参见此处

回答by ZhekaKozlov

Yes, it can be a constant. You should declare your HashMapinstance as follows:

是的,它可以是一个常数。您应该HashMap按如下方式声明您的实例:

class <class name> {
    private static final HashMap<Integer, String> tensNumberConversion = new HashMap<>();

    static {
        tensNumberConversion.put(2, "twenty");
        tensNumberConversion.put(3, "thirty");
        tensNumberConversion.put(4, "forty");
        tensNumberConversion.put(5, "fifty");
        tensNumberConversion.put(6, "sixty");
        tensNumberConversion.put(7, "seventy");
        tensNumberConversion.put(8, "eighty");
        tensNumberConversion.put(9, "ninety");
    }
}

However, this is only a constant reference. While you can not reassign tensNumberConversionto something else, you still can change the contents of your map later at runtime:

然而,这只是一个常数参考。虽然您不能重新分配tensNumberConversion给其他东西,但您仍然可以稍后在运行时更改地图的内容:

tensNumberConversion = new HashMap<>(); // won't compile
tensNumberConversion.put(9, "one"); // succeeds

If you want the contents of your map constant too, you should wrap the HashMapinto an unmodifiable map:

如果您也想要地图常量的内容,您应该将其包装HashMap到一个不可修改的地图中:

class <class name> {
    private static final Map<Integer, String> tensNumberConversion = initMap();

    private static Map<Integer, String> initMap() {
        Map<Integer, String> map = new HashMap<>();
        map.put(2, "twenty");
        map.put(3, "thirty");
        map.put(4, "forty");
        map.put(5, "fifty");
        map.put(6, "sixty");
        map.put(7, "seventy");
        map.put(8, "eighty");
        map.put(9, "ninety");
        return Collections.unmodifiableMap(map);
    }
}

回答by eckes

Just a BTW, with Java 9 there are static methods in the Mapinterfaceto create immutable Maps with some number of entries like:

顺便说一句,在 Java 9中,Map接口中静态方法可以创建具有一些条目的不可变 Map,例如:

Map<String,String> m = Map.of("k1", "v1",
                              "K2", "v2");

Or if more than 10 entries are needed:

或者如果需要超过 10 个条目:

import static java.util.Map.entry;
Map<String, String> m = Map.ofEntries(
    entry("k1", "v1"), entry("k2", "v2"), …);

回答by Jagreet

Instead of using composting to achieve a constant HashMap, you could use inheritance to inherit a new class from HashMap and then override the HashMap.put() method to display some appropriate failure message...

您可以使用继承从 HashMap 继承一个新类,然后覆盖 HashMap.put() 方法以显示一些适当的失败消息,而不是使用堆肥来实现常量 HashMap...

class MyMap extends java.util.HashMap{
@Override
public V put (K key, V value){
System.out.println("Operation Not Supported");
return null;
}
}

class MyMap extends java.util.HashMap{
@Override
public V put (K key, V value){
System.out.println("Operation Not Supported");
return null;
}
}

Note that this is not the only method but one of the many methods possible

请注意,这不是唯一的方法,而是许多可能的方法之一

回答by derHugo

I somehow missed the easiest form for direct initialization of the HashMap here

我不知何故错过了此处直接初始化 HashMap 的最简单形式

private static final Map<Integer, String> tensNumberConversion_internal = new HashMap<Integer, String>()
{
    {
        put(2, "twenty");
        put(3, "thirty");
        put(4, "forty");
        put(5, "fifty");
        put(6, "sixty");
        put(7, "seventy");
        put(8, "eighty");
        put(9, "ninety");
    };
};

and as for making it unchangeable you already have Collections.unmodifiableMapfrom the accepted answerso do

并以此为使其不变的你已经Collections.unmodifiableMap公认的答案这么做

public static final Map<Integer, String> tensNumberConversion = Collections.unmodifiableMap(tensNumberConversion_internal);

they have to be created in this order ofcourse ;)

它们必须按当然的顺序创建;)