HashMap和int作为键

124
我正在尝试构建一个哈希表,其键为整数,值为对象。
我的语法如下:

我正在尝试构建一个哈希表,其键为整数,值为对象。

我的语法是:

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

然而,错误信息显示为 - 在标记"int"之后需要维度,我不明白为什么我需要添加一个维度(即:将int变成数组),因为我只需要将数字作为键来存储。

我该怎么办?


19
HashMap 不能处理原始数据类型,只能处理对象。 - Menno
1
相关的SO问题,但是int是值而不是键。 - cyroxx
5
请使用Integer代替。 - Hot Licks
长话短说,你必须使用 Integer 类型 - 但是你可以添加键值对,就好像它允许你使用 int 类型一样。原始类型不被允许,但是 Integer 类可以处理赋值给 map 的原始类型的值。 - FoxDonut
13个回答

154

使用Integer代替。

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

Java 会自动将你的 int 基本类型值装箱为 Integer 对象。

请从 Oracle Java 文档了解更多关于 自动装箱 的信息。


11
他也不应该将一个类命名为 myObject - Adam Gent
@AdamGent 正确。所有类名应以大写字母开头,我已更正建议的代码。 - gaborsch
3
我知道你知道 :) 我只是想确保原帖作者知道/学会了。就我所知,他可能已经将变量名放在类型参数中。 - Adam Gent
2
只是一点小提示,为了节省内存并提高性能,在Android上最好使用ArrayMapSimpleArrayMap更多信息)。 - Noah Huppert

48

对于所有编写Android设备Java代码的人来说,以下内容可能会有所帮助:使用SparseArray可以提高性能。

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

使用此功能,您可以像这样使用int而不是Integer:

int newPos = 3;

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

8
请记住,SparseArray 的速度比 hashmap 慢,但更节省内存。因此,在大型数据集上不要使用它。 - TpoM6oH
稀疏数组在性能更好的同时速度较慢,如何使用它?在我的Android游戏中应该使用哪一个? - Snake
1
请记住,将元素插入到SparseArray的复杂度为**O(n)(而HashMap的复杂度为O(1)**)。当元素数量很大时,这一点非常重要。在这样的数组开头插入元素会慢得多。 - Vladimir Petrakovich
SparseArray "通常比传统的 HashMap 慢,因为查找需要二分搜索,而添加和删除需要在数组中插入和删除条目。" @Snake 参考 https://developer.android.com/reference/android/util/SparseArray.html 和 https://dev59.com/rl8e5IYBdhLWcg3wnrYQ - TT--
1
@M.kazemAkhgary 不完全准确。put() 函数在插入元素到开头时需要 O(n) 的时间(而非 n log n),因为它要先找到位置,然后移动其后的所有元素。delete() 函数本身的复杂度确实为 O(log n),但是删除后进行下一次插入或遍历操作就会导致垃圾回收,这需要 O(n) 的时间。 - Vladimir Petrakovich
显示剩余2条评论

31

你不能使用基本类型,因为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和自动装箱这样的包装器。

6

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

5

如果您对这样的地图感兴趣,因为您想要减少Java中包装器类型的自动装箱的占用空间,我建议使用Eclipse collectionsTrove不再受支持,我认为在这方面它是相当不可靠的库(尽管它仍然很受欢迎),并且无法与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 并通过索引访问值(因为映射本质上是一个关联数组)。请注意保留 html 标签。

我正在考虑使用Trove - 你为什么认为它不可靠? - Evgeniy Berezovsky
1
当我试图找到与给定问题相关的最佳库时,我遇到了一些关于Trove的错误的文章,因为它不再受支持,所以我决定不使用它。但是现在,越来越多的人在非常大的公司中使用它,我认为它并不是一个如此糟糕的选择,因为它自然被测试过(还考虑到我现在无法找到那些关于错误的文章),但我个人更愿意使用Eclipse集合。 - Alex
我明白了。同时,我已经找到了(并添加为答案)Netty库中包含的原始集合。 - Evgeniy Berezovsky

4
HashMap不允许使用原始类型作为键的主要原因在于,HashMap的设计是使用equals()方法来比较键,而该方法只能在对象上调用,而不能在原始类型上调用。
因此,当int被自动装箱为Integer时,Hashmap可以在Integer对象上调用equals()方法。
这就是为什么您应该使用Integer而不是int。也就是说,在将int作为键放入哈希表时,哈希表会抛出一个错误(不知道抛出的错误含义)。
如果您认为通过将原始类型作为键可以使Map的性能更快,那么有一个名为FastUtil的库,其中包含一种将int类型作为键的Map实现。
因此,它比HashMap快得多。

3
不,不允许使用原始类型的主要原因是 Java 中的类型擦除,这在编译期间将Map<Integer, String> 实际上转换为 Map<Object, Object>。顺便提一下,虽然 IdentityHashMap 使用 == 运算符进行相等性检查,但仍不允许使用原始类型。 - Yoory N.

4
如果您在编写Android代码,则可以使用SparseArray,它将整数映射到对象。请参考SparseArray官方文档

3

使用int作为对象而不是原始类型

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

我已经写了HashMap<Integer, MyObject> myMap = new HashMap<Integer, MyObject>(); 但是显示时,我的问题是如何使 > 和 < 显示正确的答案。 - franki3xe
我知道打字很痛苦,但我试图避免让你立即受到“-1”的惩罚。与其他人不同的是,在惩罚之前我会先发表评论(我没有给你打-1)。 - Adam Gent

2
如果您正在使用Netty并希望使用具有原始int类型键的映射,您可以使用其IntObjectHashMap
使用原始类型集合的一些原因:
  • 通过具有专门代码来提高性能
  • 减少可能会对GC施加压力的垃圾
专门集合与通用集合的问题可能会影响具有高吞吐量要求的程序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接