点进Collections.reverse的代码瞄了眼,然后就开始了一些基础知识的收集。
现在发现知道的越多,知道不知道的越多。
列几个记录下:
reverse方法源码:
/**
* Reverses the order of the elements in the specified list.<p>
*
* This method runs in linear time.
*
* @param list the list whose elements are to be reversed.
* @throws UnsupportedOperationException if the specified list or
* its list -iterator does not support the <tt>set</tt> operation.
*/
public static void reverse (List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for ( int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for ( int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
1,首先看见RandomAccess
将操作随机访问列表的最佳算法(如 ArrayList)应用到连续访问列表(如 LinkedList)时,可产生二次项的行为。如果将某个算法应用到连续访问列表,那么在应用可能提供较差性能的算法前,鼓励使用一般的列表算法检查给定列表是否为此接口的一个 instanceof,如果需要保证可接受的性能,还可以更改其行为。
现在已经认识到,随机和连续访问之间的区别通常是模糊的。例如,如果列表很大时,某些 List 实现提供渐进的线性访问时间,但实际上是固定的访问时间。这样的 List 实现通常应该实现此接口。实际经验证明,如果是下列情况,则 List 实现应该实现此接口,即对于典型的类实例而言,此循环:
for (int i=0, n=list.size(); i < n; i++)
list.get(i);
的运行速度要快于以下循环:
for (Iterator i=list.iterator(); i.hasNext(); )
i.next();
2,标记接口(marker interface)
例如,如果没有使用Iterator,遍历一个数组的方法是使用索引:
for(int i=0; i<array.size(); i++) { ... get(i) ... }
客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。
更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。
为解决以上问题,Iterator模式总是用同一种逻辑来遍历集合:
for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
奥秘在于客户端自身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。
ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator 没有此功能。
public static void main(String[] args) {
List list =new LinkedList();
for (int i = 0; i < 100000; i++) {
list.add(i);
}
int size = list.size();
long t1 = System.currentTimeMillis();
for ( int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
long t2 = System.currentTimeMillis();
System.out.println(t2 - t1);//结果1
long t3 = System.currentTimeMillis();
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for ( int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
} long t4 = System.currentTimeMillis();
System.out.println(t4 - t3);//结果2
} public static void swap(List<?> list, int i, int j) {
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
那么ArrayList 使用这两种方式的效果呢?
测试结果相差无几,随着增大数据量,swap要好于ListInterator,但是有时微乎其微,所以这个reverse代码中并没有对大数据量的ArrayList进行swap方式,减少了代码冗余,也没有降低什么性能。
---------------------------------------
还有很多扩展学习的地方,继续前进吧。