Java 为什么Collections.UnmodifiableMap.UnmodifiableEntrySet重写stream()方法?
在查看源代码时,我可以看到Java 为什么Collections.UnmodifiableMap.UnmodifiableEntrySet重写stream()方法?,java,oop,collections,java-stream,overriding,Java,Oop,Collections,Java Stream,Overriding,在查看源代码时,我可以看到stream()方法已在Collections.UnmodifiableMap.UnmodifiableEntrySet中被重写。但是代码似乎与Collection.stream()相同,除了Collections.UnmodifiableMap.UnmodifiableEntrySet.stream()中的返回类型更具体地说是stream,而不仅仅是Collection.stream()中的stream spliterator()方法在这两个类中是不同的,但是即使st
stream()
方法已在Collections.UnmodifiableMap.UnmodifiableEntrySet
中被重写。但是代码似乎与Collection.stream()
相同,除了Collections.UnmodifiableMap.UnmodifiableEntrySet.stream()
中的返回类型更具体地说是stream
,而不仅仅是Collection.stream()
中的stream
spliterator()
方法在这两个类中是不同的,但是即使stream
没有被重写,我认为如果对象的类型是UnmodifiableEntrySet
,那么UnmodifiableEntrySet.spliterator()
将从Collection.stream()
调用
那么,流
方法被重写有什么原因吗
Collection.java
@覆盖
默认拆分器拆分器(){
返回拆分器。拆分器(this,0);
}
默认流(){
返回StreamSupport.stream(spliterator(),false);
}
Collections.UnmodifiableMap.UnmodifiableEntrySet.java
@SuppressWarnings(“未选中”)
公共拆分器拆分器(){
返回新的不可修改EntrySetSpliterator(
(拆分器)c.拆分器();
}
@凌驾
公共流(){
返回StreamSupport.stream(spliterator(),false);
}
在将Collections.java
的内容复制到一个新类CollectionsCopy.java
之后,我尝试从UnmodifiableEntrySet
中删除stream
方法,然后进行了一些调试并得到了答案
UnmodifiableEntrySet
扩展了UnmodifiableSet
,它扩展了UnmodifiableCollection
,后者反过来实现了Collection
。由于UnmodifiableCollection
下面有一个字段final Collection,Java文档/程序来自openjdk 14 2020-03-17
重写spliterator
和stream
的主要原因是为了确保UnmodifiableEntrySet
的条目不被修改。
从UnmodifiableEntrySet
的注释中:
除了不可修改的集合作为映射之外,我们还需要这个类。条目本身允许通过其setValue操作修改支持映射。这个类很微妙:有许多可能的攻击必须被阻止
首先,UnmodifiableEntrySet
扩展了UnmodifiableSet
,它扩展了UnmodifiableCollection
。
在UnmodifiableCollection
中,代理模式用于避免修改backingCollection
c,大多数方法只调用backingCollection
方法,如spliterator
和stream
:
@覆盖
公共拆分器拆分器(){
返回(拆分器)c.拆分器();
}
@抑制警告(“未选中”)
@凌驾
公共流(){
返回(Stream)c.Stream();
}
因此,如果UnmodifiableEntrySet
没有覆盖这些方法,则行为将遵循UnmodifiableCollection
实现,并且支持项将被公开,并且可以通过修改
因此,spliterator
和stream
方法被覆盖,并且引入了UnmodifiableEntrySetSpliterator
,以使用UnmodifiableEntry
包装对备份条目的所有访问,确保无法修改条目
为什么不可修改的集合
覆盖流
?
似乎没有必要在不可修改的集合
中重写流
,因为我们可以在集合
中使用默认实现(只需通过拆分器创建流
)。
但是作者决定使用backingCollection c
stream
方法覆盖stream
,其中一个可能的原因是backingCollection
出于性能原因可能会覆盖stream
方法,例如Collections.CopiesList
,或者它的spliterator
方法不符合
当spliterator()方法无法返回不可变、并发或后期绑定的拆分器时,应重写此方法。(有关详细信息,请参见拆分器()
因为UnmodifiableEntrySet
是一组条目
,而集合
是通用的。“我不知道是什么把你弄糊涂了。”“是的。我的问题是,如果方法体与集合完全相同,为什么UnmodifiableEntrySet
应该重写stream()
方法。stream()
@AniketSahrawat经过一些调试后,我多少能找到一个解决方案。@Gautham-stream
不是流。另一个例子是List
不是List
。我昨天误读了你的问题。如果您查看一下流的实现,您会注意到它在7个位置被覆盖。相关覆盖位于UnmodifiableCollection
中,然后再次位于UnmodifiableEntrySet
中UnmodifiableCollection#stream
基本上是将调用委托给传递的Collection
。如果UnmodifiableEntrySet
中没有重写,则调用将委托给原始集合(该集合是可变的)。这解释了大部分调用。但我没有什么疑问这就是我试过的。在我的CollectionsCopy
类中,我已经从UnmodifiableEntrySet
和UnmodifiableCollection
中删除了覆盖的流。然后我尝试了unmodifiableMap.entrySet().stream().findFirst().orElse(null)
。这实际上返回了一个不可变的条目。如果我
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
super((Set)s);