为什么 Collections.UnmodifiableMap.UnmodifiableEntrySet 覆盖 stream() 方法?
Why does Collections.UnmodifiableMap.UnmodifiableEntrySet override the stream() method?
在查看源代码时,我可以看到 stream()
方法已在 Collections.UnmodifiableMap.UnmodifiableEntrySet
中被覆盖。但是代码似乎与 Collection.stream()
相同,除了 Collections.UnmodifiableMap.UnmodifiableEntrySet.stream()
中的 return 类型更具体为 Stream<Entry<K,V>>
而不是 Collection.stream()
中的 Stream<E>
=].
spliterator()
方法在 类 中是不同的,但即使 stream
没有被覆盖,我认为 UnmodifiableEntrySet.spliterator()
会从 [=15= 调用] 如果对象的类型是 UnmodifiableEntrySet
.
那么,stream
方法被覆盖有什么原因吗?
Collection.java
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Collections.UnmodifiableMap.UnmodifiableEntrySet.java
@SuppressWarnings("unchecked")
public Spliterator<Entry<K,V>> spliterator() {
return new UnmodifiableEntrySetSpliterator<>(
(Spliterator<Map.Entry<K, V>>) c.spliterator());
}
@Override
public Stream<Entry<K,V>> stream() {
return StreamSupport.stream(spliterator(), false);
}
将 Collections.java
的内容复制到新的 class CollectionsCopy.java
后,我尝试从 UnmodifiableEntrySet
中删除 stream
方法,然后我进行了一些调试并且能够得到答案。
UnmodifiableEntrySet
扩展了 UnmodifiableSet
,后者扩展了 UnmodifiableCollection
,后者又实现了 Collection
。由于 UnmodifiableCollection
有一个字段 final Collection<? extends E> c;
,它必须覆盖 stream()
如下
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
在 UnmodifiableEntrySet
的构造函数中,Set<? extends Map.Entry<? extends K, ? extends V>>
对象被转换为原始 Set
类型并传递给 super
构造函数。
super((Set)s);
附加到代码的评论是:
Need to cast to raw in order to work around a limitation in the type
system
因此,当我从 UnmodifiableEntrySet
中删除 stream()
(在我的 CollectionsCopy.java
中)时,由于原始类型转换,调用的 spliterator
方法是Set
而不是 UnmodifiableEntrySet
中的那个。这是因为 UnmodifiableCollection
中的字段 c
将是 Set
而不是 UnmodifiableEntrySet
并且当从 UnmodifiableCollection.stream()
调用 c.stream()
时,它会调用 Set.spliterator()
.因此,UnmodifiableEntrySet
有必要覆盖 UnmodifiableCollection
的 stream()
的实现。
此外,我尝试从 UnmodifiableCollection
中删除覆盖的 stream()
。这一次,它按预期工作,因为 spliterator
是从 UnmodifiableEntrySet
.
调用的
编辑:
根据一些评论,建议从 Collection
返回的流不会是 Entry
的流,而只是 Stream
。但在这种情况下,我不应该能够从流上的 Entry
class 调用任何方法。但是我能够在该流上调用 map(Entry::getValue)
。所以,返回的流确实是 Entry
.
类型的流
以下Java文档/程序来自openjdk 14 2020-03-17.
覆盖 spliterator
和 stream
的主要原因是确保 UnmodifiableEntrySet
的条目未被修改。
来自 UnmodifiableEntrySet
的评论:
We need this class in addition to UnmodifiableSet as Map.Entries themselves permit modification of the backing Map via their setValue operation. This class is subtle: there are many possible attacks that must be thwarted.
首先,UnmodifiableEntrySet
扩展了 UnmodifiableSet
,后者扩展了 UnmodifiableCollection
。
在UnmodifiableCollection
中,代理模式用于避免修改backing Collection
c,大多数方法只是调用backing Collection
方法,比如spliterator
和 stream
:
@Override
public Spliterator<E> spliterator() {
return (Spliterator<E>)c.spliterator();
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
因此,如果 UnmodifiableEntrySet
不重写这些方法,行为将遵循 UnmodifiableCollection
实现,并且支持条目将被公开并可以通过 Entry#setValue
.[=47 进行修改=]
因此 spliterator
和 stream
方法被覆盖并引入 UnmodifiableEntrySetSpliterator
以使用 UnmodifiableEntry
包装对支持条目的所有访问,确保无法修改条目.
为什么 UnmodifiableCollection
覆盖 stream
?
似乎没有必要覆盖 UnmodifiableCollection
中的 stream
,因为我们可以使用 Collection
中的默认实现(只需通过 spliterator
创建流).
但是作者决定使用后备 Collection c
stream
方法覆盖 stream
,可能的原因之一是后备 Collection
可能出于性能原因覆盖 stream
方法,例如Collections.CopiesList
,或者spliterator
方法不符合Collection#stream
的要求
This method should be overridden when the spliterator() method cannot return a spliterator that is IMMUTABLE, CONCURRENT, or late-binding. (See spliterator() for details.)
在查看源代码时,我可以看到 stream()
方法已在 Collections.UnmodifiableMap.UnmodifiableEntrySet
中被覆盖。但是代码似乎与 Collection.stream()
相同,除了 Collections.UnmodifiableMap.UnmodifiableEntrySet.stream()
中的 return 类型更具体为 Stream<Entry<K,V>>
而不是 Collection.stream()
中的 Stream<E>
=].
spliterator()
方法在 类 中是不同的,但即使 stream
没有被覆盖,我认为 UnmodifiableEntrySet.spliterator()
会从 [=15= 调用] 如果对象的类型是 UnmodifiableEntrySet
.
那么,stream
方法被覆盖有什么原因吗?
Collection.java
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Collections.UnmodifiableMap.UnmodifiableEntrySet.java
@SuppressWarnings("unchecked")
public Spliterator<Entry<K,V>> spliterator() {
return new UnmodifiableEntrySetSpliterator<>(
(Spliterator<Map.Entry<K, V>>) c.spliterator());
}
@Override
public Stream<Entry<K,V>> stream() {
return StreamSupport.stream(spliterator(), false);
}
将 Collections.java
的内容复制到新的 class CollectionsCopy.java
后,我尝试从 UnmodifiableEntrySet
中删除 stream
方法,然后我进行了一些调试并且能够得到答案。
UnmodifiableEntrySet
扩展了 UnmodifiableSet
,后者扩展了 UnmodifiableCollection
,后者又实现了 Collection
。由于 UnmodifiableCollection
有一个字段 final Collection<? extends E> c;
,它必须覆盖 stream()
如下
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
在 UnmodifiableEntrySet
的构造函数中,Set<? extends Map.Entry<? extends K, ? extends V>>
对象被转换为原始 Set
类型并传递给 super
构造函数。
super((Set)s);
附加到代码的评论是:
Need to cast to raw in order to work around a limitation in the type system
因此,当我从 UnmodifiableEntrySet
中删除 stream()
(在我的 CollectionsCopy.java
中)时,由于原始类型转换,调用的 spliterator
方法是Set
而不是 UnmodifiableEntrySet
中的那个。这是因为 UnmodifiableCollection
中的字段 c
将是 Set
而不是 UnmodifiableEntrySet
并且当从 UnmodifiableCollection.stream()
调用 c.stream()
时,它会调用 Set.spliterator()
.因此,UnmodifiableEntrySet
有必要覆盖 UnmodifiableCollection
的 stream()
的实现。
此外,我尝试从 UnmodifiableCollection
中删除覆盖的 stream()
。这一次,它按预期工作,因为 spliterator
是从 UnmodifiableEntrySet
.
编辑:
根据一些评论,建议从 Collection
返回的流不会是 Entry
的流,而只是 Stream
。但在这种情况下,我不应该能够从流上的 Entry
class 调用任何方法。但是我能够在该流上调用 map(Entry::getValue)
。所以,返回的流确实是 Entry
.
以下Java文档/程序来自openjdk 14 2020-03-17.
覆盖 spliterator
和 stream
的主要原因是确保 UnmodifiableEntrySet
的条目未被修改。
来自 UnmodifiableEntrySet
的评论:
We need this class in addition to UnmodifiableSet as Map.Entries themselves permit modification of the backing Map via their setValue operation. This class is subtle: there are many possible attacks that must be thwarted.
首先,UnmodifiableEntrySet
扩展了 UnmodifiableSet
,后者扩展了 UnmodifiableCollection
。
在UnmodifiableCollection
中,代理模式用于避免修改backing Collection
c,大多数方法只是调用backing Collection
方法,比如spliterator
和 stream
:
@Override
public Spliterator<E> spliterator() {
return (Spliterator<E>)c.spliterator();
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
因此,如果 UnmodifiableEntrySet
不重写这些方法,行为将遵循 UnmodifiableCollection
实现,并且支持条目将被公开并可以通过 Entry#setValue
.[=47 进行修改=]
因此 spliterator
和 stream
方法被覆盖并引入 UnmodifiableEntrySetSpliterator
以使用 UnmodifiableEntry
包装对支持条目的所有访问,确保无法修改条目.
为什么 UnmodifiableCollection
覆盖 stream
?
似乎没有必要覆盖 UnmodifiableCollection
中的 stream
,因为我们可以使用 Collection
中的默认实现(只需通过 spliterator
创建流).
但是作者决定使用后备 Collection c
stream
方法覆盖 stream
,可能的原因之一是后备 Collection
可能出于性能原因覆盖 stream
方法,例如Collections.CopiesList
,或者spliterator
方法不符合Collection#stream
This method should be overridden when the spliterator() method cannot return a spliterator that is IMMUTABLE, CONCURRENT, or late-binding. (See spliterator() for details.)