use*_*408 1 java generics collections
更改Collections.unmodifiableList为return List<? extends T>而不是List<T>将阻止在编译时添加和删除元素,而不是抛出运行时异常.
是否存在由此替代方案引起的严重问题,从而排除它?
Collections.unmodifiableList不返回的根本原因List<? extends T>是它是错误的返回类型.先来一点背景.目前的声明是
static <T> List<T> unmodifiableList(List<? extends T> list)
Run Code Online (Sandbox Code Playgroud)
请注意,这需要List<? extends T>返回List<T>.这符合Bloch的PECS原则(Naftalin/Wadler也称为put和get原理).由于返回的列表是不可修改的,因此您只能从中取出它,因此它是T类型元素的"生产者".
这为调用者提供了关于返回类型的更多灵活性.例如,人们可以这样做:
List<Double> src = Arrays.asList(1.0, 2.0, 3.0);
List<Number> list1 = Collections.unmodifiableList(src);
Run Code Online (Sandbox Code Playgroud)
这在已经存在其他功能的情况下是有用的,例如,操作List<Number>.
现在考虑一个替代声明:
static <T> List<? extends T> wildUnmodifiableList(List<? extends T> list)
Run Code Online (Sandbox Code Playgroud)
这说明了一些不同的东西.这意味着它采用T的某个子类型的列表并返回T的某个未知子类型的列表,其可能与第一类型不同.由于返回的列表是第一个列表的不可修改的视图,因此这没有任何意义.让我们用一个例子来说明:
List<Double> src = Arrays.asList(1.0, 2.0, 3.0);
List<? extends Number> list2 = wildUnmodifiableList(src);
Run Code Online (Sandbox Code Playgroud)
这意味着我们传入了一个List<Double>但是我们可能会返回一些其他类型的列表List<Integer>.同样,这没有任何意义.
当您尝试使用它时,您可以看到此声明不正确.考虑Apache Commons Collections中的IterableUtils.frequency方法:
static <E,T extends E> int frequency(Iterable<E> iterable, T obj)
Run Code Online (Sandbox Code Playgroud)
这适用于当前的声明:
List<Double> src = Arrays.asList(1.0, 2.0, 3.0);
List<Number> list1 = Collections.unmodifiableList(src);
int freq1 = frequency(list1, 0.0);
Run Code Online (Sandbox Code Playgroud)
但它失败了通配符版本:
List<Double> src = Arrays.asList(1.0, 2.0, 3.0);
List<? extends Number> list2 = wildUnmodifiableList(src);
int freq2 = frequency(list2, 0.0); // COMPILE-TIME ERROR
Run Code Online (Sandbox Code Playgroud)
原因是声明frequency要求第二个参数是第一个参数的元素类型的子类型.在第一种情况下,Double它是一个子类型Number.但在第二种情况下,Double是不的一个亚型? extends Number,导致类型不匹配.