【问题标题】:Why do Set data structures in Java use Map internally?为什么 Java 中的 Set 数据结构在内部使用 Map?
【发布时间】:2012-09-08 00:51:11
【问题描述】:

我想知道为什么HashSet 在幕后使用HashMapTreeSet 使用TreeMap,而LinkedHashSet 在内部使用LinkedHashMap?由于Set 只携带和存储密钥而不是值,所以使用额外的内存空间不是不经济吗?

HashMap 拥有的Entry 内部类如下

class Entry<K,V> implements Map.Entry<K,V> {
    final K key;
    V value;
    Entry<K,V> next;
    final int hash;
    ...
    ....
}

对于 Set,我们真的不需要 V value 变量,对吗?那么在内部使用地图对象的好处和主要原因是什么?

【问题讨论】:

    标签: java hashmap set hashset


    【解决方案1】:

    更少的代码,更少的错误,更少的测试。

    通过重复使用相同的代码,您只需优化、调试和测试一次。内存开销最小 - 每个条目的另一个指针,与 Key 相比可以忽略不计。

    【讨论】:

    • 那么我们真的可以在 Java 中说 Set = Map 吗?
    • 嗯,不,Set 是一组元素,而 map 将键映射到值。这根本不是一回事。
    • 你可以说 Set 是一个 Map ,只由值本身而不是单独的键作为键;或者至少看起来是这样的。
    • 伙计们,Set 提供的界面与 Map 提供的界面完全不同。使用 Map 实现 Set 的事实实际上只是一个技术问题。
    • 我想知道 Set 和 Map 除了 value 变量还有其他显着差异吗?
    【解决方案2】:

    使用 Map 可以简化代码,但会稍微增加内存使用量。它并不像您想象的那样多,因为开销已经很高。 ;)

    并非所有地图都有集合,您可以使用以下内容。

    Set<T> set = Collection.newSetFromMap(new ConcurrentHashMap<T>());
    Set<T> set = Collection.newSetFromMap(new ConcurrentSkipListMap<T>());
    Set<T> set = Collection.newSetFromMap(new IdentityHashMap<T>());
    

    【讨论】:

    • 其实我认为由于对齐问题,至少在 32 位 JVM 上内存使用是完全一样的。
    • 我怀疑是一样的,但这意味着在 64 位 JVM 上,每个元素有额外的 8 个字节。
    • @Peter Lawrey:你能解释一下原因吗?在所有其他条件相同的情况下,64 位 JVM 向上舍入为 8 字节而不是 4 字节的倍数,因此增加了开销,但仅在 32 位机器上。
    • 这取决于实现,但 Sun/Oracle JVM 都有 8 字节边界。在 32 位 JVM 中,您有一个 8 字节的标头,而在 64 位 JVM 中,您有一个 12 字节的标头。当您有一个具有两个 32 位引用的条目时,总大小在 32 位 JVM 上为 8+2*4 或 16 个字节,在 64 位 JVM 上为 12 +2*4 + 4 填充 = 24 个字节。即引用大小相同,但对象开销不同。
    猜你喜欢
    • 1970-01-01
    • 2022-11-20
    • 2011-10-23
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多