Thinking in Java 第四版 17.4章节中提到了可选操作。其中典型的例子之一就是Arrays.asList(),直接进来看一下是怎么回事。

 1 //java.util.Arrays
 2    /**
 3      * Returns a fixed-size list backed by the specified array.  (Changes to
 4      * the returned list "write through" to the array.)  This method acts
 5      * as bridge between array-based and collection-based APIs, in
 6      * combination with {@link Collection#toArray}.  The returned list is
 7      * serializable and implements {@link RandomAccess}.
 8      *
 9      * <p>This method also provides a convenient way to create a fixed-size
10      * list initialized to contain several elements:
11      * <pre>
12      *     List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
13      * </pre>
14      *
15      * @param <T> the class of the objects in the array
16      * @param a the array by which the list will be backed
17      * @return a list view of the specified array
18      */
19     @SafeVarargs
20     @SuppressWarnings("varargs")
21     public static <T> List<T> asList(T... a) {
22         return new ArrayList<>(a);
23     }

 

  可以看到,方法直接返回一个ArrayList,但此ArrayList非彼ArrayList,这个ArrayList是Arrays里的私有静态内部类:

 1     /**
 2      * @serial include
 3      */
 4     private static class ArrayList<E> extends AbstractList<E>
 5         implements RandomAccess, java.io.Serializable
 6     {
 7         private static final long serialVersionUID = -2764017481108945198L;
 8         private final E[] a;
 9 
10         ArrayList(E[] array) {
11             a = Objects.requireNonNull(array);
12         }
13 
14         @Override
15         public int size() {
16             return a.length;
17         }
18 
19         @Override
20         public Object[] toArray() {
21             return a.clone();
22         }
23 
24         @Override
25         @SuppressWarnings("unchecked")
26         public <T> T[] toArray(T[] a) {
27             int size = size();
28             if (a.length < size)
29                 return Arrays.copyOf(this.a, size,
30                                      (Class<? extends T[]>) a.getClass());
31             System.arraycopy(this.a, 0, a, 0, size);
32             if (a.length > size)
33                 a[size] = null;
34             return a;
35         }
36 
37         @Override
38         public E get(int index) {
39             return a[index];
40         }
41 
42         @Override
43         public E set(int index, E element) {
44             E oldValue = a[index];
45             a[index] = element;
46             return oldValue;
47         }
48 
49         @Override
50         public int indexOf(Object o) {
51             E[] a = this.a;
52             if (o == null) {
53                 for (int i = 0; i < a.length; i++)
54                     if (a[i] == null)
55                         return i;
56             } else {
57                 for (int i = 0; i < a.length; i++)
58                     if (o.equals(a[i]))
59                         return i;
60             }
61             return -1;
62         }
63 
64         @Override
65         public boolean contains(Object o) {
66             return indexOf(o) != -1;
67         }
68 
69         @Override
70         public Spliterator<E> spliterator() {
71             return Spliterators.spliterator(a, Spliterator.ORDERED);
72         }
73 
74         @Override
75         public void forEach(Consumer<? super E> action) {
76             Objects.requireNonNull(action);
77             for (E e : a) {
78                 action.accept(e);
79             }
80         }
81 
82         @Override
83         public void replaceAll(UnaryOperator<E> operator) {
84             Objects.requireNonNull(operator);
85             E[] a = this.a;
86             for (int i = 0; i < a.length; i++) {
87                 a[i] = operator.apply(a[i]);
88             }
89         }
90 
91         @Override
92         public void sort(Comparator<? super E> c) {
93             Arrays.sort(a, c);
94         }
95     }

 

  这里的确没有add等方法,首先接口里声明的方法是一定要实现的,既然不在这里那就去它的父类,AbstractList,里面寻找答案。

 1     // java.util.AbstractList
 2     public boolean add(E e) {
 3         add(size(), e);
 4         return true;
 5     }
 6 
 7 
 8     public void add(int index, E element) {
 9         throw new UnsupportedOperationException();
10     }

 

  很明显,到这里就清楚了,在这个抽象类里提供了add方法的实现——抛出UnsupportedOperationException异常。而在Arrays里返回的内部类ArrayList由于没有提供add方法的自己实现,于是你在返回的ArrayList上调用add方法实际上就是AbstractList里提供的版本。其实更直接地,可以从报错信息里看到:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)

 

  就是调用了AbstractList类的add方法,而它则“只有在运行时才会探测到”。另外,在AbstractList中set()和remove()方法都是通过这种方式实现的,“而读取方法都不是可选的”。

  这就是所谓可选操作,其原因书里有解释:

    “这样做可以防止在设计中出现接口爆炸的情况”。通过抽象类来推迟某些方法的实现,直到,需要实现的时候。

 

posted on 2017-11-28 14:15  CachedKing  阅读(245)  评论(0)    收藏  举报