1、list
首先定义了一个带有比较功能的TreeSet,每一次执行add()插入数据的时候就会进行比较,然后排序。函数
1.1分类
list分为ArrayList和LinkedList,这两者都实现了List接口,但是这两个只有这本质的区别,ArrayList底层使用的是数组,
而LinkedList
底层
使用的是链表。显然,由于这个区别,两者的使用场景和效率都有很大的不同。
1.2 ArrayList
先看一下它的类图,继承自AbstractList,实现了6个接口,这里要说一下Collection和Iterable。Collection接口是java中集合类
型数据的必要接口,Iterable接口允许我们使用foreach的方法来遍历集合。
下面是我在看api和源码过程中总结的几点
(1)ArrayList的默认初始容量为10
(2)ArrayList通过
ensure
Capacity(int x)函数来确保本身容量够大。每一次向ArrayList里面添加数据的时候,会
调用ensureCapacity(int x)看是否需要加大容量,如果要,那么就计算原长度的1.5倍然后加1,假设这个值为y,比较
参数x和y的大小,使用大的值作为ArrayList新的容量。而这里容量的改变是通过数组的新建和拷贝来完成的。在底层新建一
个数组,然后将ArrayList原来的数据拷贝过去,这样就完成了容量的增加。在即将添加大量数据的时候,可以通
过ensureCapacity这个函数设置一个大一点的容量,一次来减少之后添加大量数据时的拷贝等操作。
(3)关于同步。ArrayList不是线程安全的,如果在多线程中使用ArrayList作为共享变量,必须要在调用的时候做好同步操作,
或者在创建的时候使用 Collections.synchronizedList方法( List list = Collections.synchronizedList(new ArrayList(...)); )。
(4)快速失败机制:此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的,在创建迭代器之后,除非通过迭代器自
身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出
ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间
发生任意不确定行为的风险。
1.3 LinkedList
和ArrayList的功能不同,ArrayList更多的作为类似于可变长数组来进行使用,而LinkedList一般作为队列或者栈来使用。看下面
的实现类图,它实现了Deque(双端队列接口)和Queue(队列接口)
总结:
(1)和ArrayList一样,它也是非线程安全的,而且也有快速失败机制。
(2)可以作为队列和栈来使用,而且一般也是这么使用,因为底层是链表,所以遍历起来效率肯定不如ArrayList。
2、map
2.1 HashMap
map的子类其实有很多,但是我只用过HashMap,所以就先只看HashMap吧。HashMap里有一个加载因子的概念,当
HashMap的当前数据条数大于最大条数和加载因子的积时,HashMap就会进行数据重构,然后使HashMap拥有原来两倍
大小。HashMap的默认初始大小为16.
2.2 哈希函数
map的数据结构是一种<key,value>键值对,其底层本质上也是数组,HashMap在存放value的时候,利用key的hashcode
计算出哈希值,然后用哈希值计算出value在数组中的位置,然后将value存进去。哈希函数就是一个保证不同的hashcode可以换
成不同的哈希值的函数。
3、set
3.1 介绍
set是一个不能存放相同元素的容器,存放在set里的元素是无序的,而且每一个都是唯一的。
3.2 HashSet
HashSet是一种封装了HashMap的set,它利用HashMap实现了无序和唯一。HashSet把自己的元素存放在HashMap的key中,
利用key的唯一性实现set中数据不可重复。
3.3 遍历
HashSet不能按照下标查找,只能利用迭代器iterator进行遍历。
3.4 TreeSet
一个可以进行排序的Set,我们可以通过向TreeSet传递Comparator接口来自定义排序规则。直接看下面使用的例子:
TreeSet treeSet = new TreeSet(new Comparator() {
public int compare(Object o1, Object o2) {
Dog a = (Dog) o1;
Dog b = (Dog) o2;
return a.age>b.age?-1:(a.age == b.age?0:1) ;
}
});
Dog a = new Dog();
a.setAge(1);
a.setName("a");
Dog b = new Dog();
b.setAge(2);
b.setName("b");
Dog c = new Dog();
c.setAge(3);
c.setName("c");
treeSet.add(a);
treeSet.add(b);
treeSet.add(c);
Iterator iterator = treeSet.iterator();
while (iterator.hasNext()){
Dog dog = (Dog) iterator.next();
System.out.println(dog.name);
}
|
compare(Object
o1, Object o2)
会对o1和o2参数的age属性进行比较,o1代表的
是当前插入的数据,o2可以先不管。如果当前
插入的数据大,返回-1;小,返回1;相等,返回0。
执行上面代码的结果:
c
b
a
|
需要注意的是,如果我们让函数在相等的时候返回0,那么后加入的数据就会覆盖前面的数据。为了避免数据的丢失,我们可以在
相等的时候也返回1或-1,这样就能利用TreeSet实现排序的集合了。
3.5 TreeSet 原理
TreeSet 底层是一颗红黑树,实现原理有兴趣的话可以自行百度,其使用方法可以向上面那样。