博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java容器——未获支持的操作
阅读量:6250 次
发布时间:2019-06-22

本文共 5047 字,大约阅读时间需要 16 分钟。

    先看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import 
java.util.ArrayList;
import 
java.util.Arrays;
import 
java.util.Collection;
import 
java.util.Collections;
import 
java.util.List;
 
public 
class 
UnsupportedOperation {
    
static 
void 
test(String msg, List<String> list) {
        
System.out.println(
"----------" 
+ msg + 
"----------"
);
        
Collection<String> c = list;
        
Collection<String> subList = list.subList(
1
4
);
        
Collection<String> subList2 = 
new 
ArrayList<>(subList);
        
try 
{ c.retainAll(subList2); } 
catch 
(Exception e) {
            
System.out.println(
"retainAll: " 
+ e);
        
}
        
try 
{ c.removeAll(subList2); } 
catch 
(Exception e) {
            
System.out.println(
"removeAll: " 
+ e);
        
}
        
try 
{ c.clear(); } 
catch 
(Exception e) {
            
System.out.println(
"clear: " 
+ e);
        
}
        
try 
{ c.add(
"X"
); } 
catch 
(Exception e) {
            
System.out.println(
"add: " 
+ e);
        
}
        
try 
{ c.addAll(subList2); } 
catch 
(Exception e) {
            
System.out.println(
"addAll: " 
+ e);
        
}
        
try 
{ c.remove(
"C"
); } 
catch 
(Exception e) {
            
System.out.println(
"remove: " 
+ e);
        
}
        
try 
{ list.set(
0
"W"
); } 
catch 
(Exception e) {
            
System.err.println(
"List.set: " 
+ e);
        
}
        
System.out.println(
"List.className=" 
+ list.getClass().getSimpleName());
    
}
    
public 
static 
void 
main(String[] args) {
        
List<String> list = Arrays.asList(
"A B C D E F G"
.split(
" "
));
        
test(
"Modifiable Copy"
new 
ArrayList<String>(list));
        
test(
"Arrays.asList"
, list);
        
test(
"Unmodifiable List"
, Collections.unmodifiableList(list));
    
}
}

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
----------Modifiable Copy----------
List.className=ArrayList
----------Arrays.asList----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.className=ArrayList
----------Unmodifiable List----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.set: java.lang.UnsupportedOperationException
List.className=UnmodifiableRandomAccessList

    那么为什么会出现这样的结果呢?对于Unmodifiable的List不能做修改很好理解,但从结果中可以看到,同样是ArrayList,为什么Array.asList()返回的List就不能做修改呢?

    Arrays.asList()会生成一个List,它基于一个固定大小的数组,仅支持那些不会改变数组大小的操作,任何对引起底层数据结构的尺寸进行修改的方法都会产生一个UnsupportedOperationException异常,以表示对未获支持操作的调用。

    其实上面的代码中,我故意使用的是getSimpleName(),因为这个方法不会显示包名。如果我们将

1
System.out.println(
"List.className=" 
+ list.getClass().getSimpleName());

    替换为:

1
System.out.println(
"List.className=" 
+ list.getClass().getName());

    那么结果就是这样的了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
----------Modifiable Copy----------
List.className=java.util.ArrayList
----------Arrays.asList----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.className=java.util.Arrays$ArrayList
----------Unmodifiable List----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.className=java.util.Collections$UnmodifiableRandomAccessList
List.set: java.lang.UnsupportedOperationException

    可以看到,Arrays.asList返回的名字虽然叫ArrayList,但此ArrayList是Arrays中的一个内部类,而非java.util.ArrayList。

查看其源码,可以发现此Arrays.ArrayList内部类的声明如下:

1
2
private 
static 
class 
ArrayList<E> 
extends 
AbstractList<E>
        
implements 
RandomAccess, java.io.Serializable

    而该类的实现方法中,并没有实现修改E[]数组(增、删、清除等)的方法

    因此对这种对象调用这些方法时会调用AbstractList类中的实现,于是就直接抛出了UnsupportedOperationException:

    因此,通常的做法是,把Arrays.asList()的结果作为构造方法的参数传递给任何Collection(或者使用addAll()方法或Collections.addAll()静态方法),这样就可以生成允许使用所有的方法的普通容器——这在main()中的第一个对test()的调用中得到了展示,这样的调用会产生新的尺寸可调的底层数据结构。Collections类的“不可修改”方法将容器包装到了一个代理中,只要你执行任何试图修改容器的操作,这个代理就会产生UnsupportedOperationException异常。使用这些方法的目标就是产生“常量”容器对象。

    test()中的最后一个try语句块将检查作为List的一部分set()方法。Arrays.asList()返回固定尺寸的List,而Collections.unmodifiableList()产生不可修改的列表。正如输出中看到的,修改Arrays.asList()返回的List中的元素是可以的,因为这没有违反“尺寸固定”这一特性。但很明显,unmodifiableList()的结果在任何情况下都是不可修改的。

--------------------------------------------------------------

    像上述抛出异常的操作,在Java容器中被称为“未获支持的操作”。那么为什么会将方法定义为可选的呢?那是因为这样做可以防止在设计中出现接口爆炸的情况。为了让这种方式能工作:

    1. UnsupportedOperationException必须是一种罕见的事件。即,对于大多数类来说,所有操作都应该可以工作,只有在特例中才会有这类操作。在Java容器中也确实如此,因为你在99%的时间里使用的容器类,如ArrayList、LinkedList、HashSet和HashMap,以及其他的具体实现,都支持所有的操作。

    2. 如果一个操作是未获支持的,那么在实现接口的时候可能就会导致UnsupportedOperationException异常,而不是将产品交付给客户以后才出现此异常,这种情况是有道理的,毕竟,它表示编程上有错误:使用了不正确的接口实现。

    值得注意的是,这类操作只有在运行时才能探测到。

转载地址:http://mrfsa.baihongyu.com/

你可能感兴趣的文章
Markdown语法
查看>>
《CSS世界》读书笔记(十六)
查看>>
初入前端
查看>>
(回文串 )Best Reward -- hdu -- 3613
查看>>
最少拦截系统------LCS--------动态规划
查看>>
关于EOF的种种。
查看>>
h5 拍照上传 代码
查看>>
javascript 通用定义
查看>>
语文文法
查看>>
SSM(Spring,SpringMVC,MyBatis)用户登录
查看>>
关于SQL注入,你应该知道的那些事
查看>>
jquery bxslider幻灯片样式改造
查看>>
常用JavaScript操作页面元素的方法
查看>>
学习进度条 12/18 到12/23
查看>>
varnish学习以及CDN的原理
查看>>
服务器配置 隐藏apache和php的版本
查看>>
将数据表中的数据导出到Excel、将Excel中的数据导入到数据表
查看>>
数据恢复系列(1)~恢复方案制定
查看>>
ASCII码值表
查看>>
关于Python中继承的格式总结
查看>>