一、集合概述Collection
1、集合用于存储对象。
与数组的区别:集合是可变长度的,且类型不固定,只要是对象就行。可以存储不同类型的对象。
2、集合体系结构:
Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的数组结构。特点:查询速度很块,但是增删稍慢,数越多越明显。
线程不同步。效率高。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询很慢。
|--Vector:底层使用数组数据结构。比集合框架出现还早。线程同步,被ArrayList替代了。
|--Set:元素是无序的,元素不可以重复。
|--HashSet:底层数据结构是哈希表。线程非同步。
保证元素唯一性的原理:判断元素的hashCode值是否相等,如果相同,还会继续判断元素的equals方法。
|--TreeSet:底层数据结构是二叉树,左边小,又变大。可以对set集合中的元素进行排序。
具体如下图:
3、为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都有不同,这个存储方式可以称之为:数据结构。
每个容器数据结构不同,所以分不同的容器。
二、集合中常用的共性方法
1、基本方法:add(),addAll(),clear(),remove()。
boolean add(E e),添加对象,方法的参数类型是Object,以便于接受任意类型的对象。
int size(),计算集合长度。
void clear(),清空容器(集合)。
boolean contains(Object o),是否包含对象o。
boolean isEmpty(),这个集合是不是为空,也可以用size是不是0来判断。
boolean remove(Object o),删除该对象元素。
boolean removeAll(Collection<?> c),删除交集。
boolean retainAll(Collection<?> c),保留交集。
集合中存放的是对象的引用(地址),不是对象实体。数组也是这样。
2、迭代器
(1)使用Iterator方法的代码,这里al是一个集合类型对象:
高效规范:for(Iterator it = al.iterator;it.hasNext();){ it.next();}
习惯写法:Iterator it = al.iterator; while(it.hasNext()){it.next();}
(2)迭代器其实就是集合取出元素的方式。
由于每个容器对元素的取出方式不同,就把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素。
那么取出方式就被定义成了内部类。而每一个容器的数据结构不同,所以取出的动作细节也不一样。
但是都具有共性内容:判断和取出。那么可以将共性抽取。这些内部类都符合一个规则,该规则就是Iterator。
通过对外提供一个方法:iterator()获取取出对象。
注意:在迭代时循环中next调用一次,就要hasNext判断一次,不可以同时使用next两次。
三、List派系
1、List:元素是有序的,元素可以重复,因为该集合体系有索引。
2、特有的方法,凡是以操作角标的方法都是List体系中特有的方法。
增:
add(int index,E element);
addAll(int index,Collection<? extends E> c);
删:
remove(int index);
改:
set(int index,E element);
查:
get(int index);
sublist(int fromIndex,int toIndex);
listIterator();
indexOf(Object o);获取对象的位置
3、List集合特有的迭代器:ListIterator,它是Iterator的子接口。
用法跟Iterator用法基本一致,但是功能更加强大,不仅可以遍历,还可以对遍历的元素进行其他操作,
如对集合元素的增删改查操作。这是Iterator所做不到的。使用ListIterator还可以逆向获取和操作。hasPrevious(),previous()。
同时使用迭代器和集合操作集合元素,会出现并发修改异常。不能对同一组元素进行多种同时操作。
ListIterator的出现是为解决这个问题。
4、Vector中的枚举。
这里的枚举,就是Vector特有的取出方式。它和迭代器很像,之后被迭代器取代了。
Vector通过elements()方法返回它的
5、LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询很慢。
特有方法:
addFirst(); addLast();
getFirst(); getLast();//获取元素,集合为空时会抛出NoSuchElementException异常。
removeFirst(); removeLast();//获取元素,同时元素被删除。如果集合为空,会抛出如上异常。
offerFirst(); offerLast();
peekFirst(); peekLast();//获取元素,不删除元素。如果集合为空,则会返回null。
pollFirst(); pollLast();//获取元素,之后删除元素。如果集合为空,则会返回null。
LinkedList练习:
使用LinkedList模拟一个堆栈或者队列的数据结构。堆栈:先进后出; 队列:先进先出。
思路:使用addLast方法依次存入,使用removeFirst方法依次取出。
枚举,通过hasMoreElements()和nextElement()方法获取枚举中的元素。6、ArrayList练习:
(1)ArrayList可变长度数组,默认为十,百分之五十增长,Vector百分之百增长。
(2)取出集合中的重复元素。
思路:新定义另外一个ArrayList集合,然后依次遍历源ArrayList集合,如果新集合不包含则将该对象存入新集合,
如果包含则跳过。
(3)将自定义对象作为元素存到ArrayList集合中,并去除重复元素。
思路同上。
注意:contains()方法依据的就是对象中的equals()方法,remove()方法也调用了对象的equals方法。
所以需要重对象的类中的equals方法。
7、不同容器的选用规则:
如果查询使用较多,使用ArrayList;如果增删使用较多,查询较少,使用LinkedList。如果都有,建议首选ArrayList,因为大量增删操作还是不多见的。
四、Set派系
1、Set:元素是无序的,元素不可以重复。Set和Collection的方法一样。
|--HashSet:底层数据结构是哈希表。线程非同步。
|--TreeSet:可以对set集合中的元素进行排序。
2、HashSet:
(1)保证元素唯一性的原理:判断元素的hashCode值是否相等,如果相同,还会继续判断元素的equals方法,是否为true。
(2) 注意:对于判断元素是否存在,以及删除等操作,HashSet依赖的方法是元素的hashCode和equals方法。
(3)而ArrayList依赖的只是equals方法。这跟使用的数据结构不同有关系。
HashSet练习:
HashSet存储自定义对象。根据需求重写hashCode和equals方法。
3、TreeSet:
(1)TreeSet集合存储的元素必须要有比较性。比较性可以让要存入TreeSet的对象的类实现接口Comparable,复写compareTo方法;也可以让TreeSet使用构造器Comparator:TreeSet<Student> t = new TreeSet<Student>(new Comparator(){});
(2)记住:排序时,当主要条件相同时,一定判断一下次要条件。当两种排序都存在时,以比较器为主。
一般建议使用构造器来实现Treeset排序。