为什么Map.values()返回抽象实现?

时间:2019-06-19 11:20:55

标签: java collections

Map<Integer, String> map = new TreeMap<>();
map.put(1, "String1");
map.put(2, "String2");
map.put(3, "String3");

我想转换map的值来设置。我知道我可以轻松做到

Set<String> set = new HashSet<>(map.values());

考虑这个问题时,我很好奇map.values()到底是什么?所以我尝试了

System.out.println("Set:"+ (map.values() instanceof Set));      
System.out.println("List:"+ (map.values() instanceof List));    
System.out.println("Queue:"+ (map.values() instanceof Queue));
System.out.println("SortedSet:"+ (map.values() instanceof SortedSet));

输出令人惊讶地是

Set:false
List:false
Queue:false
SortedSet:false

This是所有文档说明的内容。

  

此地图中包含的值的集合视图

然后我查看了反编译的类文件。

public Collection<V> values() {
    if (values == null) {
        values = new AbstractCollection<V>() {
            public Iterator<V> iterator() {
                return new Iterator<V>() {
                    private Iterator<Entry<K,V>> i = entrySet().iterator();

                    public boolean hasNext() {
                        return i.hasNext();
                    }

                    public V next() {
                        return i.next().getValue();
                    }

                    public void remove() {
                        i.remove();
                    }
                };
            }

            public int size() {
                return AbstractMap.this.size();
            }

            public boolean isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object v) {
                return AbstractMap.this.containsValue(v);
            }
        };
    }
    return values;
}

为什么Java返回抽象实现而不是可以立即与用例兼容的List / Set / Queue

3 个答案:

答案 0 :(得分:5)

我不知道您使用的是哪个Java版本,但是我看不到values()返回的抽象类实例。它返回TreeMap.Values的实例,该实例是扩展AbstractCollection的类。

关于为什么它不返回Set的原因-这仅是由于值的集合可能包含重复项,而Set不允许重复。

List也不理想,因为这暗示着值是有序的,这对于所有Map实现(例如HashMap)都不正确。

顺便说一句,您不必打印map.values() instanceof Set之类的东西,而只需打印map.value().getClass().getName()就可以看到实际的实现类。

答案 1 :(得分:3)

仅从实现上看有一个原因:containsiterator都查看映射的当前内容,而不是调用values()时的映射内容。 / p>

如果您呼叫values(),然后更改地图中的某些内容,则更改将反映在最初从Collection返回的values()中。

Map<String, String> map = new HashMap<String, String>();
map.put("some", "thing");
Collection<String> values = map.values();
System.out.println(values.size()); // 1
map.put("foo", "bar");
System.out.println(values.size()); // 2

答案 2 :(得分:1)

哈希集在内部使用HashMap,因此在场景中不会出现太多的值副本。

您可以查看相关链接以获取更多信息。 Reference Link

抽象收集的地方,下面是从Java Doc获取的一些相关信息:

1]此类提供Collection的骨架实现   接口,以最小化实现此接口所需的工作。

2]要实现不可修改的集合,程序员只需要   扩展此类并为<tt>iterator</tt>提供实现   <tt>size</tt>个方法。 (<tt>iterator</tt>返回的迭代器   方法必须实现<tt>hasNext</tt><tt>next</tt>

3]要实现可修改的集合,程序员必须另外   覆盖此class's <tt>add</tt>方法(否则将抛出   UnsupportedOperationException),然后由   迭代器方法必须另外实现其remove   方法。

希望这会有所帮助。