【问题标题】:In Java, can I declare a HashMap constant?在 Java 中,我可以声明一个 HashMap 常量吗?
【发布时间】:2017-10-09 21:56:00
【问题描述】:

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

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

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

...并使用索引访问它,但我想尝试使用这样的 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");

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

我尝试将其设为私有静态最终哈希图,但 IntelliJ 给了我一个错误(此处不允许使用修饰符“私有”……“静态”也是如此)。

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

【问题讨论】:

  • 它可以是一个常数,你在哪里声明你的HashMap
  • 据我所见,我在5月12日接受了您的答复。和你看到的不一样吗?

标签: java hashmap constants


【解决方案1】:

是的,它可以是一个常数。您应该如下声明您的 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");
    }
}

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

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

如果您也想要地图常量的内容,您应该将 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);
    }
}

【讨论】:

  • 现在好多了。
【解决方案2】:

这里有两个方面:

  • 您有一个包含对地图的引用的变量。您只需将该变量声明为 final;瞧,您不能将变量更改为指向 另一个 引用。
  • 但这并不妨碍您更改引用指向的对象的状态。因此,即使您有一个 final Map 对象,您仍然可以在该 Map 上调用 put/remove/... 方法。

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

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

然后您使用Collections.unmodifiableMap() 来创建一个无法再更改的地图。

需要注意的一件事:您必须确保您没有泄漏对原始地图对象的引用,因为该不可变地图只是该初始地图的包装。例如,您可以使用一些辅助方法来做到这一点。

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

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

【讨论】:

  • Collections.unmodifiableMap
【解决方案3】:

顺便说一句,在 Java 9 中,static methods in the Map interface 可以创建包含一些条目的不可变地图,例如:

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

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

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

【讨论】:

【解决方案4】:

我不知何故错过了这里直接初始化 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");
    };
};

至于使其不可更改,您已经拥有来自the accepted answerCollections.unmodifiableMap,所以这样做

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

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

【讨论】:

【解决方案5】:

您可以使用继承从 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;
}
}

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

【讨论】:

  • 但这基本上是 Collections.unmodifiableMap 返回的地图已经做了 - 除了它抛出而不是假装工作 - 所有修改方法都会抛出 UnsupportedOperationException。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 2020-07-27
  • 1970-01-01
  • 2011-05-09
相关资源
最近更新 更多