Java集合API:为什么Unmodifiable [List | Set | Map]不是公开可见的类?

jav*_*top 20 java api collections unmodifiable

Collections.unmodifiableList(...)返回静态内部类 的新实例UnmodifiableList.其他不可修改的集合类以相同的方式构造.

如果公开这些课程,一个有两个好处:

  • 能够指示更具体的返回值(例如UnmodifiableList),因此API用户不会想到修改该集合;
  • 能否在运行时检查是否Listinstanceof UnmodifiableList.

那么,是否有任何优势不让这些课程公开?

编辑:没有提出绝对令人信服的论据,所以我选择了最受欢迎的答案.

oxb*_*kes 7

我个人完全同意你的意见.问题的核心是Java的泛型不是协变的,而这反过来又是因为Java的集合是可变的.

这是不可能的Java的类型系统编纂一类,似乎有改变者实际上不变.想象一下,如果我们开始设计一些解决方案:

interface Immutable //marker for immutability

interface ImmutableMap<K, V> extends Map<K, V>, Immutable
Run Code Online (Sandbox Code Playgroud)

但是它ImmutableMap是一个子类Map,因此Map可以从ImmutableMap任何返回这种不可变Map的方法中赋值:

public ImmutableMap<K, V> foo();
Run Code Online (Sandbox Code Playgroud)

可以分配给Map,因此可以在编译时进行变异:

Map<K, V> m = foo();
m.put(k, v); //oh dear
Run Code Online (Sandbox Code Playgroud)

所以,你可以看到这种类型的添加实际上并没有阻止我们做任何坏事.我认为由于这个原因,我们判断它没有足够的价格.


scala这样的语言具有声明站点方差注释.也就是说,你可以将一个类型指定为协变(因而是不可变的),就像Scala的Map一样(实际上它在V参数中是协变的).因此,您的API可以声明其返回类型是可变的还是不可变的.

另外,Scala允许您声明交集类型,以便您甚至不需要将ImmutableXYZ接口创建为单独的实体,您可以指定要返回的方法:

def foo : XYZ with Immutable
Run Code Online (Sandbox Code Playgroud)

但是scala有一个合适的类型系统,而Java没有


Chr*_*tze 5

我认为这两个优点都存在,但不是那么有用。主要问题保持不变:UnmodifiableList 仍然是一个 List,因此所有 setter 都可用,并且底层集合仍然可以修改。公开类 UnmodifiableList 会增加不可修改的错觉。

更好的方法是让编译器提供帮助,但为此必须对集合类层次结构进行大量更改。例如,Scala 的集合 API 在这方面要先进得多。

一个缺点是在 API 中引入了至少三个额外的类/接口。由于它们没有那么有用,我认为将它们排除在 API 之外是一个不错的选择。