HashMap 和 int 作为键

Posted

技术标签:

【中文标题】HashMap 和 int 作为键【英文标题】:HashMap and int as key 【发布时间】:2013-04-15 10:35:40 【问题描述】:

我正在尝试构建一个 HashMap,它将整数作为键,对象作为值。

我的语法是:

HashMap<int, myObject> myMap = new HashMap<int, myObject>();

但是,返回的错误是 - 标记“int”的语法错误,此标记之后的尺寸 - 我不明白为什么我应该添加一个维度(即:将 int 放入数组中),因为我只需要存储一个数字作为键。

我能做什么?

提前致谢! :)

【问题讨论】:

HashMap 不处理原语,只处理对象。 Related SO question,但 int 是值,而不是键。 改用Integer 长话短说,您必须使用整数 - 但您可以添加键,就好像它允许您使用整数一样。不允许使用基元,但 Integer 类将处理分配给地图的基元值。 【参考方案1】:

请改用Integer

HashMap<Integer, MyObject> myMap = new HashMap<Integer, MyObject>();

Java 会自动将您的 int 原始值自动装箱为 Integer 对象。

从 Oracle Java 文档中了解更多关于 autoboxing 的信息。

【讨论】:

他也不应该给一个班级命名myObject @AdamGent 正确。所有类名都应以大写开头,我更正了推荐的代码。 我知道你知道 :) 我只是想确保 OP 知道/学习。据我所知,他本可以在类型参数中添加一个变量名。 只是一个简短的小说明,最好在android上使用ArrayMapSimpleArrayMap以节省内存并提高性能(More information)【参考方案2】:

对于为 Android 设备编写 Java 并最终来到这里的每个人:使用 SparseArray 以获得更好的性能;

private final SparseArray<myObject> myMap = new SparseArray<myObject>();

有了这个,你可以使用 int 而不是 Integer 之类的;

int newPos = 3;

myMap.put(newPos, newObject);
myMap.get(newPos);

【讨论】:

请记住,SparseArray 比 hashmap 慢,但内存效率更高。所以,不要在大型​​数据集上使用它。 SparseArray 如何在速度较慢的情况下获得更好的性能?在我的安卓游戏中使用哪一个 @Snake SparseArray 如果您像使用HashMap 那样分配一堆内存装箱和拆箱整数,则虚拟机将需要尽快暂停执行以进行垃圾收集。如果您想频繁且快速地做某事,这一点很重要。 请记住,插入SparseArray 的复杂度为 O(n)HashMap 的复杂度为 O(1))。当元素数量很大时,这一点很重要。插入此类数组的开头要慢得多。 @M.kazemAkhgary 不完全是。 put() 在开始时将 O(n)(不是 n log n)插入,因为它找到位置,然后移动所有后续元素。 delete() 本身确实需要O(log n),但删除后的下一次插入或迭代元素将需要使用O(n) 的垃圾回收。【参考方案3】:

您不能使用原语,因为 HashMap 在内部使用对象作为键。所以只能使用继承自 Object 的对象(即任何对象)。

这是 HashMap 中的 put() 函数,你可以看到它使用 Object 表示 K:

public V put(K key, V value) 
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) 
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        
    

    modCount++;
    addEntry(hash, key, value, i);
    return null;

表达式“k = e.key”应该清楚。

我建议使用像 Integer 和 autoboxing 这样的包装器。

【讨论】:

【参考方案4】:

您可以尝试使用 Trove http://trove.starlight-systems.com/ TIntObjectHashMap 可能就是你要找的。​​p>

【讨论】:

【参考方案5】:

HashMap 不允许原始数据类型作为参数。它只能接受对象所以

HashMap<int, myObject> myMap = new HashMap<int, myObject>();

不会工作。

您必须将声明更改为

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();

所以即使您执行以下操作

myMap.put(2,myObject);

原始数据类型自动装箱为 Integer 对象。

8 (int) === boxing ===> 8 (Integer)

您可以在此处阅读有关自动装箱的更多信息http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

【讨论】:

【参考方案6】:

HashMap 不允许原语作为键的主要原因是 HashMap 的设计方式是为了比较键,它使用 equals() 方法,并且方法只能在对象上调用,不能在原语上调用。

因此当int被自动装箱为Integer时,Hashmap可以调用Integer对象的equals()方法。

这就是为什么你应该使用 Integer 而不是 int。我的意思是hashmap在将int作为键时抛出错误(不知道抛出的错误的含义)

如果您认为,可以通过将原语作为键来提高 Map 性能,有一个名为 FastUtil 的库,其中包含一个带有 int 的 Map 实现键入作为键。

正因为如此,它比 Hashmap

快得多

【讨论】:

不,不允许原始类型的主要原因是 Java 中的type erasure,它在编译期间有效地将Map&lt;Integer, String&gt; 转换为Map&lt;Object, Object&gt;。顺便说一句,IdentityHashMap 使用 == 运算符进行相等性检查,但仍然不允许原始类型。【参考方案7】:

如果您在 Android 中编码,则有 SparseArray,将整数映射到对象。

【讨论】:

【参考方案8】:

对于那些对此类地图感兴趣的人,因为您想减少 Java 中 autoboxing 的足迹 对原始类型的包装器,我建议使用 Eclipse collections。 不再支持Trove,我认为它在这个意义上是非常不可靠的库(尽管它仍然很受欢迎)并且无法与Eclipse collections相比。

import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap;

public class Check 
    public static void main(String[] args) 
        IntObjectHashMap map = new IntObjectHashMap();

        map.put(5,"It works");
        map.put(6,"without");
        map.put(7,"boxing!");

        System.out.println(map.get(5));
        System.out.println(map.get(6));
        System.out.println(map.get(7));
    

在上面这个例子中IntObjectHashMap。

当您需要 int->object 映射时,还可以考虑使用 YourObjectType[] 数组或 List&lt;YourObjectType&gt; 并按索引访问值(因为映射本质上是一个关联数组)。

【讨论】:

我正在考虑使用 Trove - 为什么您认为它不可靠? 当我试图找到与给定问题相关的最佳库时,我遇到了一些关于 trove 错误的文章,由于不再支持,我决定不使用它。但是现在,在非常大的公司中遇到越来越多的人使用它,我不会认为它是一个如此糟糕的选择,因为它自然地经过测试可以这么说(同时考虑到我现在找不到那些关于错误的文章),但我自己更愿意使用 Eclipse 集合。 我明白了。与此同时,我发现(并添加为answer)Netty 库中包含的原始集合【参考方案9】:

将 int 用作 Object 而不是原始类型

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();

【讨论】:

我写过 HashMap myMap = new HashMap();但是显示使我的问题与 > 和 我知道打字很痛苦,但我试图将您从即时-1 中拯救出来。我不像其他人在惩罚之前发表评论(我没有 -1 你)。【参考方案10】:

如果你在使用 Netty 并且想使用带有原始 int 类型键的映射,你可以使用它的IntObjectHashMap

使用原始类型集合的一些原因:

通过专门的代码提高性能 减少对 GC 造成压力的垃圾

专业化集合与通用化集合的问题可以决定具有高吞吐量要求的程序的成败。

【讨论】:

【参考方案11】:

请使用 HashMap&lt;Integer, myObject&gt; myMap = new HashMap&lt;Integer, myObject&gt;();

【讨论】:

【参考方案12】:

我不明白为什么我应该添加一个维度(即:将 int 变成一个数组),因为我只需要存储一个数字作为键。

数组也是一个对象,因此HashMap&lt;int[], MyObject&gt; 是一个使用 int 数组作为键的有效构造。

编译器不知道你想要什么或你需要什么,它只是看到一个几乎正确的语言结构,并警告它缺少什么是完全正确的。

【讨论】:

注意这一点,一个数组的哈希值与它的内容无关,所以两个内容相同的数组可以哈希到不同的值,这使得它成为一个很差的键。

以上是关于HashMap 和 int 作为键的主要内容,如果未能解决你的问题,请参考以下文章

使用对象或整数作为 HashMap 键更好吗?

如何使 HashMap 以数组为键工作?

实现一个简易的HashMap

HashMap

java中的HashMap类是做啥用的?

Java HashMap类源码解析