【问题标题】:How to avoid using implementation types for HashMap如何避免使用 HashMap 的实现类型
【发布时间】:2015-08-13 09:55:44
【问题描述】:

以前是

 public static final Map<BigInteger, String> CONTRACT_STATUS_LIST = new HashMap<BigInteger, String>()

改变后

public static final Map<BigInteger, String> CONTRACT_STATUS_LIST = new HashMap<BigInteger, String>(){{
    put(Constants.STATUS_CANCELLED, "Cancelled");
    put(Constants.STATUS_TERMINATED, "Terminated");
}};

收到错误消息:

Class definition changed (and this is unsupported)
Added elements: public static final java.util.Map com.Constants.CONTRACT_STATUS_LIST
Removed elements: public static final java.util.HashMap com.Constants.CONTRACT_STATUS_LIST
java.lang.RuntimeException: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)

【问题讨论】:

  • Offtopic:您不想将BigInteger 用于任何类型的枚举键。这些对象是巨大的,当你想要的只是在你的常量类中的十几个甚至一千个键实例中唯一的值时。更喜欢 int/Integer 或枚举或类似的东西。
  • @hiergiltdiestfu:实际上,正如你所说的那样,这个场景在十几个甚至上千个对象中是独一无二的。所以我更喜欢使用 BigInteger 而不是 Integer/int。这个问题有解决办法吗跨度>
  • 为什么?你有可能超过 2E32 个元素吗?
  • @hiergiltdiestfu:public static final BigInteger STATUS_CANCELLED = BigInteger.valueOf(9134254847713154879L);公共静态最终 BigInteger STATUS_TERMINATED = BigInteger.valueOf(9134254847713154885L); id是这样的
  • 这些高数字是从外部强加给您的吗?在任何情况下,这些仍然适合long/Long(最高约 +9,223*10^18)。我只是想强调 BigInteger 大约有 10 个整数那么重,并且经常用于不需要的地方。

标签: java hashmap


【解决方案1】:

您似乎正试图将某种默认值放入该静态地图中。

这应该在一个单独的静态初始化块中完成,放置在字段初始化之后:

public static final Map<BigInteger, String> CONTRACT_STATUS_LIST = new HashMap<BigInteger, String>();

static {
    CONTRACT_STATUS_LIST.put(Constants.STATUS_CANCELLED, "Cancelled");
    CONTRACT_STATUS_LIST.put(Constants.STATUS_TERMINATED, "Terminated");
};

顺便说一句:您很可能不想将BigInteger 用于任何类型的枚举键。这些对象是巨大的,当您想要的只是在您的Constants 类中的十几个甚至一千个键实例中唯一的值时。更喜欢 int/Integerenum 或类似的东西。

编辑:关于BigInteger 的足迹的旁白是基于 jdk7 的,并且在 cmets 中受到了挑战。我对 jdk8u45 中的整数范围值做了一个简单的基准测试,发现足迹 Integer 与 BigInteger 的系数为 3,诚然这不再是“巨大的”了。尽管如此,在我看来,BigInteger 应该只在需要对大数进行算术运算时使用。相反,我总是尝试使用简单的类型,包括 String(对于在基准测试中测试的范围,平均仍然使用比 BigInteger 少 8 个字节)。 (范围 [0,100k[, Integer~15B, Long~30B, String~40B, BigInteger~48B 的平均值)

【讨论】:

  • 实际上没有理由BigInteger 应该很大。存储的数据扩展以满足使用int[] 存储的数字的要求,但如果数字可以适合int,则不分配数组。
  • @OldCurmudgeon 你是对的,它可能会根据需要扩展实际值字段,但从 jdk8u45 开始,每个 BigInteger 类仍然包含几个额外的 int 字段,用于缓存有关值的元数据。我承认我最后一次查看内存占用可能是在一些 jdk7 中,但当时我记得每个 BigInteger 计算了大约 10 个相关的 int 属性,不管表示的值是多少。
  • @OldCurmudgeon 在 8u45 上做了一个快速基准测试(使用 Runtime#freeMemory()):在 int-Range 中分配 100k Ints、Longs 和 BigIntegers 提供了这些数字:一个 Integer 大约需要 17 个字节,一个 Long 30B 和一个 BigInteger 占用大约 48 个字节。这不像以前那么令人印象深刻,但对于可以表示为整数且不需要大数算术的东西,它仍然是因子 3。
【解决方案2】:

以下代码运行良好:

public class Test {
    public static final Map<BigInteger, String> CONTRACT_STATUS_LIST = new HashMap<BigInteger, String>(){{
        put(BigInteger.ONE, "Cancelled");
        put(BigInteger.ZERO, "Terminated");
    }};

    public static void main(String[] args) {
        System.out.println(CONTRACT_STATUS_LIST.toString());
    }
}

【讨论】:

    猜你喜欢
    • 2013-01-02
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多