前言:上次我们分析Collection接口的一些通用功能,还有一些源码的简单分析,接下来我们继续从上往下分析,了解每个接口的特性,以及每个接口下面的实现类底层源码是如何实现的.
官方描述:
该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。
首先List接口继承了Collection接口,是一个有序的集合与Set集合相反,增加了一些索引位置的相关操作。
下面我们在介绍一下用工厂的方式创建List集合
List.of()
静态工厂方法提供了一种创建不可变列表的方便方法。 由这些方法创建的List
实例具有以下特征:
UnsupportedOperationException
被抛出。 但是,如果包含的元素本身是可变的,则可能会导致列表的内容出现更改。null
元素。 尝试使用null
元素创建它们将导致NullPointerException
。==
),身份哈希码和同步)是不可靠的,应该避免。public class Demo1_Collecton {
public static void main(String[] args) {
List<String> a = List.of("a", "b");
List<Integer> b = List.of(1, 3);
System.out.println(a);
System.out.println(b);
}
}
注意这个新特性是缺点的,我们不能修改,不能删除和添加,只能查看,如果执行插入操作的话,编译不报错,运行报错,错误如下:
UnsupportedOperationException 不支持操作异常 ,所以这个快速创建集合的方式,一般很少用。
* @author Josh Bloch
* @author Neal Gafter
* @see Collection
* @see Set
* @see ArrayList
* @see LinkedList
* @see Vector
* @see Arrays#asList(Object[])
* @see Collections#nCopies(int, Object)
* @see Collections#EMPTY_LIST
* @see AbstractList
* @see AbstractSequentialList
* @since 1.2
*/
public interface List<E> extends Collection<E> {
我们看到特也是一个接口,继承了Collection接口,也就是,继承了Collection的所有通用方法,往下都是一些方法,我们选一些金典的分析一下
/**
* Returns an immutable list containing four elements.
*
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
*
* @param <E> the {@code List}'s element type
* @param e1 the first element
* @param e2 the second element
* @param e3 the third element
* @param e4 the fourth element
* @return a {@code List} containing the specified elements
* @throws NullPointerException if an element is {@code null}
*
* @since 9
*/
static <E> List<E> of(E e1, E e2, E e3, E e4) {
return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
}
我们看看静态化工厂是如何快速创建集合元素的。
class ImmutableCollections {
/**
* A "salt" value used for randomizing iteration order. This is initialized once
* and stays constant for the lifetime of the JVM. It need not be truly random, but
* it needs to vary sufficiently from one run to the next so that iteration order
* will vary between JVM runs.
*/
static final int SALT;
static {
long nt = System.nanoTime();
SALT = (int)((nt >>> 32) ^ nt);
}
它是通过ImmutableCollections这个类来创建的,并且这个静态抽象类继承了AbstractList<E>实现了
RandomAccess, Serializable
abstract static class AbstractImmutableList<E> extends AbstractList<E>
implements RandomAccess, Serializable {
@Override public boolean add(E e) { throw uoe(); }
@Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
@Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
@Override public void clear() { throw uoe(); }
@Override public boolean remove(Object o) { throw uoe(); }
@Override public boolean removeAll(Collection<?> c) { throw uoe(); }
@Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
@Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); }
@Override public boolean retainAll(Collection<?> c) { throw uoe(); }
@Override public void sort(Comparator<? super E> c) { throw uoe(); }
}
重写一些常用的方法,而每个方法都抛出同一个异常,我们也从根源,找到了,它为啥,就是不能添加删除等等,因为每当对这个新创建的集合操作是,都会有异常出现。
static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
我们看看Sort()这个方法
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
将对象转化为数组,调用Arrays数组工具类的sort方法传入这个转化的数组进行排序,然后调用List Iterator迭代器进行遍历,进行相应的操作,等下次有时间我们在一起探究一下数组工具类sort是如何排序的,它的底层又是实现的,有二分搜索,有快排等等,这些内容很精彩,他们都是一个个小世界,我要去探究探究。
@Override
default Spliterator<E> spliterator() {
if (this instanceof RandomAccess) {
return new AbstractList.RandomAccessSpliterator<>(this);
} else {
return Spliterators.spliterator(this, Spliterator.ORDERED);
}
}
我们可以看到这是一个默认并行迭代器的使用,首先我们探究一下if中this instanceof RandomAccess是是么作用,我们点击RandomAccess查看它的源码
public interface RandomAccess {
}
这是一个空接口,这个很闹心?为啥要设计一个空接口呢,为什么,它有何作用,一系列的问题都迎面而来,我们自己百度看看资料,我们可以知道空接口的作用一般是起到一个标识的作用。
通俗点讲,就是判断一个list是否实现了RandomAcess接口,如果实现了,采用下面所示的简单的for循环进行访问速度比较快:
for (int i=0, n=list.size(); i < n; i++) list.get(i);
如果未实现RandomAcess接口,则采用下面的iterator循环访问速度比较快。
for (Iterator i=list.iterator(); i.hasNext(); ) i.next();
判断使用instanceof,即
if (list instanceof RandomAccess)
至此我们就大概理解了为什么它要实现这个空接口,因为List要访问元素,for循环和iterator的访问速度不同
下篇我们继承List接口实现类的核心源码探究