<>举个栗子
本章示例代码来自java编程思想——17.4.1未获支持的操作——Unsupported类。
import java.util.*; public class Unsupported { static void test(String msg,
List<String> list) { System.out.println("--- " + msg + " ---"); Collection<
String> c = list; Collection<String> subList = list.subList(1,8); // Copy of
the sublist: Collection<String> c2 = new ArrayList<String>(subList); try { c.
retainAll(c2); } catch(Exception e) { System.out.println("retainAll(): " + e); }
try { c.removeAll(c2); } 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(c2); } catch(Exception e) { System.out.println("addAll(): "
+ e); } try { c.remove("C"); } catch(Exception e) { System.out.println(
"remove(): " + e); } // The List.set() method modifies the value but // doesn't
change the size of the data structure: try { list.set(0, "X"); } catch(
Exception e) { System.out.println("List.set(): " + e); } } public static void
main(String[] args) { List<String> list = Arrays.asList("A B C D E F G H I J K
L".split(" ")); test("Modifiable Copy", new ArrayList<String>(list)); test(
"Arrays.asList()", list); test("unmodifiableList()", Collections.
unmodifiableList( new ArrayList<String>(list))); } } /* Output: --- Modifiable
Copy --- --- 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 --- unmodifiableList() --- 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 *///:~
在主函数内先用Arrays这个工具类的asList方法生成了一个List。在调用静态函数test方法时,先后测试了3种List:
* ArrayList的构造器,构造器签名是:public ArrayList(Collection<? extends E> c)。
* Arrays工具类的静态方法asList方法,其方法签名是public static <T> List<T> asList(T... a)。
* Collections工具类的静态方法unmodifiableList方法,其方法签名是public static <T> List<T>
unmodifiableList(List<? extends T> list)。
这3种List的定义分别在:
* ArrayList
* Arrays$ArrayList(注意是Arrays的静态内部类)
* Collections$UnmodifiableRandomAccessList(注意是Collections的静态内部类)
在静态方法test中,有一句Collection<String> subList = list.subList(1,8),这个list是传入的形参,其类型是
List<String>。而List<E>接口中的subList方法是没有默认实现的,这意味着上面测试的3种List都是把subList
方法进行了各自的实现了的。实现的位置分别在:
* ArrayList里。
* 本应该在Arrays$ArrayList里,但由于没有override,所以实现在Arrays$ArrayList的父类AbstractList里。
* Collections$UnmodifiableList里或者Collections$UnmodifiableRandomAccessList
里(都是Collections的静态内部类),由于主函数传参是new ArrayList<String>(list))
(ArrayList继承了标记接口RandomAccess),所以静态方法unmodifiableList方法返回的是
Collections$UnmodifiableRandomAccessList的实例。
关于subList的各自实现本文不会深究,读者只需要知道List<E>接口中的subList方法签名是:List<E> subList(int
fromIndex, int toIndex)即可。
静态方法test里,就是去测试类型为List<String>的传入形参list,看它是否对于List<E>接口里的各个可选操作是否都进行了实现。当
List<E>的实现类不支持这些可选操作时,其实现会是直接抛出UnsupportedOperationException异常。
从打印结果来看:
* ArrayList
支持所有的可选操作(因为一个UnsupportedOperationException异常都没有捕获到),所以要想拥有完备的功能,还是得使用ArrayList
啊。
* Arrays$ArrayList除了set()操作外,都不支持。
* Collections$UnmodifiableRandomAccessList都不支持,名副其实的Unmodifiable不可修改。
<>Arrays.asList()源码
public class Arrays { /*省略*/ public static <T> List<T> asList(T... a) { return
new ArrayList<>(a);//调用静态内部类的构造器 } /** * @serial include */ private static class
ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.
Serializable//看起来和真正的ArrayList好像差不多 { private static final long serialVersionUID
= -2764017481108945198L; private final E[] a;//内部实现只是个数组 ArrayList(E[] array) {
a= Objects.requireNonNull(array); } @Override public int size() { return a.
length; } @Override public Object[] toArray() { return a.clone(); } @Override
@SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) {//不是可选操作哦,成员的泛型方法
int size = size(); if (a.length < size)//如果传入数组大小<成员数组大小,那么直接忽略传入数组,返回一个新的数组
return Arrays.copyOf(this.a, size,//新的数组大小和成员数组大小一样 (Class<? extends T[]>) a.
getClass()); System.arraycopy(this.a, 0, a, 0, size);//如果传入数组大小>=成员数组大小,执行这句 if
(a.length > size)//如果传入数组大小>成员数组大小 a[size] = null; return a; } @Override public
Eget(int index) { return a[index];//依靠数组的取下标操作 } @Override public E set(int
index, E element) { E oldValue = a[index]; a[index] = element; return oldValue;
} @Override public int indexOf(Object o) { E[] a = this.a; if (o == null) { for
(int i = 0; i < a.length; i++) if (a[i] == null) return i; } else { for (int i =
0; i < a.length; i++) if (o.equals(a[i])) return i; } return -1; } @Override
public boolean contains(Object o) { return indexOf(o) != -1; } @Override public
Spliterator<E> spliterator() { return Spliterators.spliterator(a, Spliterator.
ORDERED); } @Override public void forEach(Consumer<? super E> action) { Objects.
requireNonNull(action); for (E e : a) { action.accept(e); } } @Override public
void replaceAll(UnaryOperator<E> operator) { Objects.requireNonNull(operator); E
[] a = this.a; for (int i = 0; i < a.length; i++) { a[i] = operator.apply(a[i]);
} } @Override public void sort(Comparator<? super E> c) { Arrays.sort(a, c); } }
/*省略*/ }
Arrays.asList返回了一个fixed-size固定大小的List,它继承AbstractList时除了实现了必要的get() & size()
外,还实现了set()方法,毕竟set()方法不会违背fixed-size这个概念。
但是这个静态内部类没有去overrideadd() & remove(),这意味着它将使用继承于AbstractList
的实现——直接抛出UnsupportedOperationException异常。所以在使用Arrays.asList返回的List时一定要注意到,add()
& remove()方法我们是不能使用的。
在toArray方法里面,可能会调用到Arrays.copyOf()方法。
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]
> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (
Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(
newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength)); return copy; }
三目表达式里,先判断(Object)newType == (Object)Object[].class)的返回值,这里是想判断一下传入的Class
对象的类型标签是否为Object[],如果是那就好办了,直接创建Object的数组——new Object[newLength]。但其类型标签如果不是
Object[],又想创建新数组,那就必须用到Array.newInstance了(注意是反射包里的java.lang.reflect.Array)。
之所以一定要用三目表达式而不直接使用Array.newInstance,我个人猜想是:使用反射来创建数组必定有着效率的问题,而如果类型标签就是Object[]
,那么就没有必要使用反射了,直接创建Object数组就可以更快执行。
注意在给Arrays.asList传参时,不能将基本类型数组作为参数。
import java.util.Arrays; import java.util.List; public class test1 { public
static void main(String[] args) { int[] myArray = { 1, 2, 3 }; List myList =
Arrays.asList(myArray); System.out.println(myList.size()); } }
代码打印结果居然是1,而debug也看出来,myList的元素类型居然是int[3]。之所以打印结果不是3、且myList的元素类型不是int
,是因为asList 方法签名:
public static <T> List<T> asList(T... a)
可见其形参类型是T的可变参数,虽然java的自动拆装箱配合泛型方法的类型推断
,能在单个基本类型时起到作用,但是遇到了基本类型的数组时,自动拆装箱就会失效了,所以List myList = Arrays.asList(myArray)
这里,程序认为你只传入了一个参数,且这个参数的类型是int[]。
相对的,在单个基本类型时,java的自动拆装箱就可以配合泛型方法的类型推断一起搞事情了,比如List myList = Arrays.asList(4)
这句,debug效果如下:
<>Collections.unmodifiableList()源码
public static <T> List<T> unmodifiableList(List<? extends T> list) { return (
listinstanceof RandomAccess ? new UnmodifiableRandomAccessList<>(list) : new
UnmodifiableList<>(list)); }
unmodifiableList方法先判断形参list是否属于RandomAccess的,RandomAccess是一个标记接口,代表可以随机存取,比如一般List就可以随机访问(其实就是其内部实现是数组,数组取下标操作当然就是随机访问了),而Set就不可以随机访问。根据是否属于RandomAccess,返回相应的实例。
static class UnmodifiableList<E> extends UnmodifiableCollection<E> implements
List<E> { private static final long serialVersionUID = -283967356065247728L;
final List<? extends E> list; UnmodifiableList(List<? extends E> list) { super(
list); this.list = list; } public boolean equals(Object o) {return o == this ||
list.equals(o);} public int hashCode() {return list.hashCode();} public E get(
int index) {return list.get(index);}//非可选操作里,就实现了get public E set(int index, E
element) {//其他的非可选操作,都是抛异常 throw new UnsupportedOperationException(); } public
void add(int index, E element) { throw new UnsupportedOperationException(); }
public E remove(int index) { throw new UnsupportedOperationException(); } public
int indexOf(Object o) {return list.indexOf(o);} public int lastIndexOf(Object o)
{return list.lastIndexOf(o);} public boolean addAll(int index, Collection<?
extends E> c) { throw new UnsupportedOperationException(); } @Override public
void replaceAll(UnaryOperator<E> operator) { throw new
UnsupportedOperationException(); } @Override public void sort(Comparator<? super
E> c) { throw new UnsupportedOperationException(); } public ListIterator<E>
listIterator() {return listIterator(0);} public ListIterator<E> listIterator(
final int index) { return new ListIterator<E>() { private final ListIterator<?
extends E> i = list.listIterator(index); public boolean hasNext() {return i.
hasNext();} public E next() {return i.next();} public boolean hasPrevious() {
return i.hasPrevious();} public E previous() {return i.previous();} public int
nextIndex() {return i.nextIndex();} public int previousIndex() {return i.
previousIndex();} public void remove() {
//当然,ListIterator也直接抛异常,如果改成调用i成员的remove,可能不会抛异常的 throw new
UnsupportedOperationException(); } public void set(E e) { throw new
UnsupportedOperationException(); } public void add(E e) { throw new
UnsupportedOperationException(); } @Override public void forEachRemaining(
Consumer<? super E> action) { i.forEachRemaining(action); } }; } public List<E>
subList(int fromIndex, int toIndex) { return new UnmodifiableList<>(list.subList
(fromIndex, toIndex)); } /** * UnmodifiableRandomAccessList instances are
serialized as * UnmodifiableList instances to allow them to be deserialized *
in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). * This method
inverts the transformation. As a beneficial * side-effect, it also grafts the
RandomAccess marker onto * UnmodifiableList instances that were serialized in
pre-1.4 JREs. * * Note: Unfortunately, UnmodifiableRandomAccessList instances *
serialized in 1.4.1 and deserialized in 1.4 will become * UnmodifiableList
instances, as this method was missing in 1.4. */ private Object readResolve() {
return (list instanceof RandomAccess ? new UnmodifiableRandomAccessList<>(list)
: this); } } /** * @serial include */ static class UnmodifiableRandomAccessList<
E> extends UnmodifiableList<E> implements RandomAccess {
UnmodifiableRandomAccessList(List<? extends E> list) { super(list); } public
List<E> subList(int fromIndex, int toIndex) { return new
UnmodifiableRandomAccessList<>( list.subList(fromIndex, toIndex)); } private
static final long serialVersionUID = -2542308836966382001L; /** * Allows
instances to be deserialized in pre-1.4 JREs (which do * not have
UnmodifiableRandomAccessList). UnmodifiableList has * a readResolve method that
inverts this transformation upon * deserialization. */ private Object
writeReplace() { return new UnmodifiableList<>(list); } }
UnmodifiableList的实现其实就是套一个壳子而已,所以操作都依赖于构造器里传入的那个List。
UnmodifiableList是名副其实的不可修改,那些常用操作里面,它就只实现了get()方法,连set()都不让用。注意
Collections$unmodifiableList还继承了Collections$UnmodifiableCollection,后者已经帮忙实现了
size() isEmpty() contains() iterator()
等方法,当然它的实现风格也是让很多方法抛UnsupportedOperationException异常。
UnmodifiableRandomAccessList的实现就简单,直接继承UnmodifiableList就好了。注意这二者的区别就是:
UnmodifiableRandomAccessList代表了可随机访问,UnmodifiableList代表了不可以随机访问。
注意到,UnmodifiableRandomAccessList有一个writeReplace
方法必然返回一个非随机访问的不可修改列表;而UnmodifiableList有一个readResolve
方法可能返回一个随机访问的不可修改列表。从这两个方法的逻辑可以理解出:随机访问的列表可以直接转换为非随机访问的列表(writeReplace
方法),但非随机访问的列表要想转换为随机访问的列表的前提是,此列表原本就是可随机访问的(readResolve
方法)。这种关系就类似于父类对象和子类对象之间的互相转换。

技术
©2019-2020 Toolsou All rights reserved,
LeetCode-67-二进制求和-C语言Unity 简单手机小游戏 - 3D重力滚球(源码)web前端的登陆页面制作Linux下内存检测工具:asan超级绚丽,20款前端动画特效,轰炸你的眼睛小老板管理常识没想到 Google 排名第一的编程语言,为什么会这么火?编程是一种思想,而不是敲代码jenkins与k8s实战麻将胡牌算法