151建议五

63ArrayList数组扩容

ArrayList是一个大小可变的数组, 但它在底层使用的是数组存储(也就是elementData变量)

实现动态长度必然要进行长度的扩展,ensureCapacity方法提供了此功能

在达到elementData长度的临界点时,才将elementData扩容1.5倍

当Vector(线程安全)或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小

elementData的默认长度是10,

默认初始化时声明了一个长度为10的数组, 在通过add方法增加第11个元素时, ArrayList类就自动扩展了,新的elementData数组长度是( 10×3) /2+1, 也就是16, 当增加到第17个元素时再次扩容为( 16×3) /2+1, 也就是25, 依此类推, 实现了ArrayList的动态数组管理

50人左右, 我们就声明ArrayList的默认容量为50的1.5倍( 元素数量小, 直接计算, 避免数组拷贝) ,即new ArrayList<Studeng>( 75) , 这样在使用add方法增加元素时, 只要在75以内都不用做数组拷贝,超过了75才会按照默认规则扩容

64数组去重排序取最大第二大

1
2
3
4
5
6
7
8
//转换为列表
List<Integer>
dataList=Arrays.asList( data) ;
//转换为TreeSet, 删除重复元素并升序排列
TreeSet<Integer>ts=new TreeSet<
Integer>( dataList) ;
//取得比最大值小的最大值, 也就是老二了
return ts.lower( ts.last( ) ) ;

65注意基本类型数组转换列表陷阱

1
2
3
4
public static<T>List<T>
asList( T……a) {
return new ArrayList<T>( a) ;
}

asList方法输入的是一个泛型 变长参数, 我们知道基本类型是不 能泛型化的, 也就是说8个基本类 型不能作为泛型参数, 要想作为泛 型参数就必须使用其所对应的包装 类型

 

原始类型数组不能作为asList的输入参数, 否则会引起程序逻辑混乱

 

66asList方法产生的List对象不可更改

asList方法内的ArrayList非 java.util.ArrayList, 而是Arrays工具 类的一个内置类它没有提供add方法,asList返回的是一个长度不可变的列表

67列表的遍历方法

Java为ArrayList类加上了 RandomAccess接口ArrayList是随机存取 的, 采用下标方式遍历列表速度会 更快

有些List实现类不是随机存取的, 而是有序存取的, 比如LinkedList类, LinkedList也是一 个列表, 但它实现了双向链表, 每 个数据结点中都有三个数据项: 前 节点的引用( Previous Node) 、 本 节点元素( Node Element) 、 后继 节点的引用( Next Node)使用foreach方式效率更高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static int average( List<
Integer>list) {
int sum=0;
if( list instanceof RandomAccess) {
//可以随机存取, 则使用下标遍历
for( int i=0, size=list.size( ) ; i<
size; i++) {
sum+=list.get( i) ;
}}
else{
//有序存取, 使用foreach方式
for( int i: list) {
sum+=i;}}/
/除以人数, 计算平均值
return sum/list.size( ) ;
}

68频繁插入和删除时使用LinkedList

LinkedList的插入效率比ArrayList快
50倍以上

处理大批量的删除动作, LinkedList比ArrayList快40倍以上

70subList产生的列表只是一个视图, 所有的修改动作直接作用于原列表

使用subList处理局部列表

1
2
3
4
5
6
7
8
9
10
11
public static void
main( String[]args) {
//初始化一个固定长度, 不可变列表
List<Integer>
initData=Collections.nCopies( 100, 0) ;
//转换为可变列表
ArrayList<Integer>list=new
ArrayList<Integer>( initData) ;
//删除指定范围的元素
list.subList( 20, 30) .clear( ) ;
}

72生成子列表后不要再操作原列表

防御式编程就是教我们如此做的。

1
2
3
4
5
6
7
8
9
List<String>list=new ArrayList<
String>( ) ;
List<String>
subList=list.subList( 0, 2) ;
//设置列表为只读状态list=Collections.unmodifableList( lis
//对list进行只读操作
doReadSomething( list)
//对subList进行读写操作
doReadAndWriteSomething( subList)

subList生成子列表后,保持原列表的只读状态

可以有多个子列表, 但问题是只要生成的子列表多于一个, 则任何一个子列表就都不能修改了, 否则就会抛出ConcurrentModificationException异常

73JAVA中的排序

Comparable接口可以作为实现类的compareTo默认排序法,

Comparator接口则是一个类的扩展 排序工具,Collections.sort方 法, 它有一个重载方法 Collections.sort( List<T>list, Comparator<?super T>c) , 可以 接受一个Comparator实现类

根据自然排序,先职位后id(使用apache的工具类来简化处理)

1
2
3
4
5
6
7
public int compareTo( Employee o) {
return new CompareToBuilder()
.append( position, o.position) //职
位排序
.append( id,
o.id) .toComparison() ; //工号排序
}

75 indexOf依赖equals方法查找,binarySearch则依赖compareTo方法查找

实现了compareTo方法, 就应该覆写equals方法, 确保两者同步

76集合运算时使用更优雅的方式

//1并集list1.addAll( list2) ;

//2交集 list1.retainAll( list2) ;

//3差集 list1.removeAll( list2) ;

1
2
3
4
5
//4无重复的并集
//删除在list1中出现的元素
list2.removeAll( list1) ;
//把剩余的list2元素加到list1中
list1.addAll( list2) ;