HashMap.keySet() return 如何查看键值?
How can HashMap.keySet() return a view of keys?
这里是 java.util.HasMap class 中的 keySet() 函数:
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
评论里说的是这个功能
Returns a {@link Set} view of the keys contained in this map.
The set is backed by the map, so changes to the map are
reflected in the set, and vice-versa.
因此,我期望 KeySet 类型的对象,此函数 returns 将包含对 "view of keys" 的引用。
但是,当我查看代码时,KeySet class 根本不包含任何字段,而且它的所有超级 class 也是如此。
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
有人可以解释一下吗
- "a view of the keys"是什么意思? "a view"是什么数据?
- HashMap.keySet() returns 如何使用根本不包含任何引用的 KeySet 对象查看键?
为了更清楚:
这里是打印键集值的代码示例。尽管 KeySet 对象持有对包含地图数据的引用,但这怎么能准确地输出键数据而不是地图的其他数据(不是值数据或其他任何数据)。是什么东西告诉这个 KeySet 对象只保存 MapKeys?我在它的代码中看不到这样的指令。
package com.tutorialspoint;
import java.util.*;
public class HashMapDemo {
public static void main(String args[]) {
// create hash map
HashMap newmap = new HashMap();
// populate hash map
newmap.put(1, "tutorials");
newmap.put(2, "point");
newmap.put(3, "is best");
// get keyset value from map
Set keyset = newmap.keySet();
// check key set values
System.out.println("Key set values are: " + keyset);
}
}
输出:
Key set values are: [1, 2, 3]
“view”是一种对象,其数据由不同的对象支持,但以不同的方式提供。在这种情况下,它提供 Map
的键的 "view" 作为 Set
。这对用户和性能都有很多好处。
值得注意的是,由于它与支持 class 共享其数据,因此内存开销非常小 - 它不需要将所有密钥复制到一个全新的 Set
中。此外,用户无需担心视图与支持结构不同步 - 添加和删除将立即通过视图可见。
因为 KeySet
是一个 inner class 它可以访问包含 class (HashMap
) 的实例的字段。请注意代码段中的 HashMap.this
符号。
size()
的 return size;
是对 HashMap
的 size
字段的引用
clear()
的HashMap.this.clear();
调用了HashMap
的clear()
方法(需要用HashMap.this
引用地图的clear()
方法而不是它自己的)
contains()
委托 HashMap
的 containsKey()
方法 - 这不需要 HashMap.this
因为 KeySet
没有碰撞 containsKey()
方法
remove()
类似地委托给 HashMap
的 removeNode()
如果它被声明为 final static class KeySet
,它将是一个静态嵌套的 class,它不依赖于包含 class 的实例(这只是一种组织方式相关 classes)。在那种情况下 KeySet
需要一个明确的 HashMap
字段,并且需要将有问题的地图传递给构造函数。内部 classes 使这一点变得隐含(简洁,但有时确实令人困惑)。
What is the thing that tells this KeySet object to hold only MapKeys?
需要说明的是,没有这样的指令。 KeySet
实例可传递地访问支持映射的所有字段和方法。但是,您的示例 (System.out.println("Key set values are: " + keyset);
) 正在隐式调用 keyset.toString()
,这(有意)未实现为 return 地图的值。因为 KeySet
扩展了 AbstractSet
(进而扩展了 AbstractCollection
)它的 .toString()
依赖于 KeySet
的 iterator()
实现,它提供了一个迭代器在地图的键上,而不是它的值上。
这里是 java.util.HasMap class 中的 keySet() 函数:
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
评论里说的是这个功能
Returns a {@link Set} view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.
因此,我期望 KeySet 类型的对象,此函数 returns 将包含对 "view of keys" 的引用。 但是,当我查看代码时,KeySet class 根本不包含任何字段,而且它的所有超级 class 也是如此。
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
有人可以解释一下吗
- "a view of the keys"是什么意思? "a view"是什么数据?
- HashMap.keySet() returns 如何使用根本不包含任何引用的 KeySet 对象查看键?
为了更清楚:
这里是打印键集值的代码示例。尽管 KeySet 对象持有对包含地图数据的引用,但这怎么能准确地输出键数据而不是地图的其他数据(不是值数据或其他任何数据)。是什么东西告诉这个 KeySet 对象只保存 MapKeys?我在它的代码中看不到这样的指令。
package com.tutorialspoint;
import java.util.*;
public class HashMapDemo {
public static void main(String args[]) {
// create hash map
HashMap newmap = new HashMap();
// populate hash map
newmap.put(1, "tutorials");
newmap.put(2, "point");
newmap.put(3, "is best");
// get keyset value from map
Set keyset = newmap.keySet();
// check key set values
System.out.println("Key set values are: " + keyset);
}
}
输出:
Key set values are: [1, 2, 3]
“view”是一种对象,其数据由不同的对象支持,但以不同的方式提供。在这种情况下,它提供
Map
的键的 "view" 作为Set
。这对用户和性能都有很多好处。值得注意的是,由于它与支持 class 共享其数据,因此内存开销非常小 - 它不需要将所有密钥复制到一个全新的
Set
中。此外,用户无需担心视图与支持结构不同步 - 添加和删除将立即通过视图可见。因为
KeySet
是一个 inner class 它可以访问包含 class (HashMap
) 的实例的字段。请注意代码段中的HashMap.this
符号。size()
的return size;
是对HashMap
的size
字段的引用clear()
的HashMap.this.clear();
调用了HashMap
的clear()
方法(需要用HashMap.this
引用地图的clear()
方法而不是它自己的)contains()
委托HashMap
的containsKey()
方法 - 这不需要HashMap.this
因为KeySet
没有碰撞containsKey()
方法remove()
类似地委托给HashMap
的removeNode()
如果它被声明为
final static class KeySet
,它将是一个静态嵌套的 class,它不依赖于包含 class 的实例(这只是一种组织方式相关 classes)。在那种情况下KeySet
需要一个明确的HashMap
字段,并且需要将有问题的地图传递给构造函数。内部 classes 使这一点变得隐含(简洁,但有时确实令人困惑)。What is the thing that tells this KeySet object to hold only MapKeys?
需要说明的是,没有这样的指令。
KeySet
实例可传递地访问支持映射的所有字段和方法。但是,您的示例 (System.out.println("Key set values are: " + keyset);
) 正在隐式调用keyset.toString()
,这(有意)未实现为 return 地图的值。因为KeySet
扩展了AbstractSet
(进而扩展了AbstractCollection
)它的.toString()
依赖于KeySet
的iterator()
实现,它提供了一个迭代器在地图的键上,而不是它的值上。