转载:java
一:集合的概念程序员
集合:保存数量不肯定的数据,以及保存具备映射关系的数据的容器,简单的理解就是用于存储数量不等的多个对象的容器。算法
集合和数组不同,数组元素既能够是基本类型的值,也能够是对象(对象的引用变量);而集合里只能保存对象(对象的引用变量)。编程
Java集合类主要由两个集合框架的根接口派生而出:Collection和Map数组
Java中Collection接口的体系机构:安全
Collection接口和Iterator接口:数据结构
Collection接口是List、Set和Queue接口的父接口,该接口中定义了一些操做集合元素的方法:框架
下面列举一些常见的方法:ide
boolean add(Object o):该方法用于向集合里添加一个元素。函数
boolean addAll(Collection c):该方法把集合c里的全部元素添加到指定的集合里。
void clean():清除集合里的全部元素,将集合长度变为0。
boolean contains():返回集合里是否包含指定元素。
boolean containsAll():返回集合里是否包含集合c里的全部元素。
boolean isEmpty():返回集合是否为空。当集合长度为0时返回true,不然返回false。
Iterator iterator():返回一个Iterator对象,用于遍历集合中的元素。
boolean remove(Object o):删除集合中指定的元素o,当集合中包含了一个或多个元素o时,这些元素将被删除,该方法将返回true。
boolean removeAll(Collection c):从集合中删除集合c里包含的全部元素。
boolean retainAll(Collection c):从集合中删除集合c里不包含的元素(至关于取得把调用该方法的集合变为该集合和集合c的交集),若是该操做改变了调用该方法的集合,返回true。
int size():该方法返回集合里元素的个数。
Object[] toArray():该方法把集合转换成一个数组,全部集合元素变成对应的数组元素。
Iterator接口:
Iterator接口也是Java集合框架的成员,但它与Collection系列、Map系列的集合不同:Collection系列集合和Map系列的集合主要用于盛装其余对象,而Iterator则主要用于遍历集合的元素。又叫迭代器。
Iterator接口隐藏了各类Collection实现类的底层细节,只向应用程序提供遍历集合元素的统一编程接口。
Iterator接口定义了三个方法:
boolean hasNext():若是被迭代的集合元素还有没遍历,则返回true。
Object next():返回集合里的下一个元素。
void remove():删除集合里上一次next方法返回的元素。
Iterator仅用于遍历集合,若是须要建立Iterator对象,则必须有一个被迭代的集合。没有集合和Iterator仿佛无本之木,没有存在的意义。
当使用Iterator对集合元素进行迭代时,Iterator并非把集合元素本事传给了迭代变量,而是把集合元素的值传给了迭代变量,因此修改迭代变量的值对集合元素本事没有影响。
当使用Iterator来迭代访问Collection集合元素时,Collection集合里的元素不能被修改,只能经过remove方法删除上次next方法返回的集合元素才能够,不然报java.util.ConcurrentModificationException异常。
Iterator迭代器采用的是快速失败(fail-fast)机制,一旦在迭代过程当中检测到该集合已经被修改(一般是其余线程进行修改),程序将报java.util.ConcurrentModificationException异常。而不是显示修改后的结果,这样能够避免共享资源而引起的问题。
foreach循环变量集合元素
格式:
for(类型 新对象:集合){
}
用法和Iterator相似。
二:Set接口
Set集合是无顺序的,其集合元素不容许重复。
Set集合判断两个对象相同不是使用==运算符,而是根据equals方法。简单的说,若是只要两个对象用equals方法比较返回true,Set集合就不会接受这两个对象;反之,则成立。
HashSet类:
HashSet是Set集合的实现类,HashSet按Hash算法来存储集合中的元素,所以具备很好的存取和查找性能。
HashSet集合特色:
(1)不能保证元素的排列顺序,顺序有可能发生变化。
(2)HashSet不是同步的,若是多个线程同时访问一个HashSet,若是有2条或2条以上线程同时修改HashSet集合时,必须经过代码实现线程同步。
(3)集合元素值能够是null。
向HastSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来获得该对象的hashCode值,而后根据该HashCode值来决定该对象在HashSet中存储位置。若是有两个元素经过equals方法比较返回true,但它们的hashCode()方法返回值不相等,HashSet将会把它们存储在不一样的位置,就能够添加成功(简单的理解HastSet集合判断两个元素是否相等的标准是两个对象经过equals方法比较相等,且两个对象的hashCode()方法返回的值也要相等)。
TreeSet类:
TreeSet是SortedSet接口的惟一实现,TreeSet能够确保集合元素处于排序状态。
TreeSet新添的方法:
(1)Comparator comparator():返回当前Set使用的Comparator,或者返回null,表示以天然方式排序。
(2)Object first():返回集合中的第一个元素。
(3)Object last():返回集合中的最后一个元素。
(4)Object lower(Object e):返回集合中位于指定元素以前的元素。
(5)Object higher(Object e):返回集合中位于指定元素以后的元素。
(6)SortedSet subSet(fromElement,toElement):返回此Set的子集合,范围冲fromElement(包含)到toElement(不包含)。
(7)SortedSet headSet(toElement):返回此Set的子集,由小于toElement的元素组成。
(8)SortedSet tailSet(fromElement):返回此Set的子集,由大于或等于fromElement的元素组成。
TreeSet集合并非根据元素的插入顺序进行排序,而是根据元素实际值进行排序。
TreeSet集合采用红黑树的数据结构对元素进行排序。TreeSet集合支持两种排序方法:天然排序和定制排序。默认使用天然排序。
天然排序
TreeSet调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,而后将集合元素按升序排列,这就是天然排序。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数,实现该接口的类必须实现该方法,当一个对象调用该方法与另外一个对象进行比较时,好比:obj1.compareTo(obj2),若是该方法返回0,则代表两个对象相等,若是返回是一个正整数,则代表obj1大于obj2,若是返回是一个负数,则代表obj1小于obj2。
注意:向TreeSet集合中添加元素时,只有第一个元素能够不实现Comparable接口,后面添加的全部元素都必须实现Comparable接口。不然报ClassCastException异常。
当把一个对象加入TreeSet集合中时,TreeSet调用该对象的compareTo方法与集合中的其余对象比较大小,而后根据红黑树算法决定它存储的位置。若是两个对象相等,TreeSet将把他们存储在同一位置。TreeSet集合比较两个对象相等的标准是:两个对象经过equals方法返回true,或经过compareTo方法比较返回0,则认为两个对象是同一个对象。
定制排序
经过实现Comparator接口中的compare方法来实现集合的定制排序,
int compare(T o1,T o2)方法比较大小,若是返回是正整数,则代表o1大于o2,若是返回0,则代表两个对象相等,若是返回负数,则代表o1小于o2。
若是须要实现定制排序,则须要在建立TreeSet集合对象时,并提供一个Comparator对象与该集合关联,由该Comparator对象负责集合的排序逻辑。
经典实例
public class TreeSetTest {
public static void main(String[] args) {
//定义TreeSet集合,并为集合提供一个排序的Comparator对象(这里是匿名内部类)。
TreeSet<M> ts = new TreeSet<M>(new Comparator<M>() {
@Override
public int compare(M m1, M m2) {
// TODO Auto-generated method stub
if (m1.num > m2.num) {
return -1;//这是按降序排序,若是想按升序排序,这里返回正整数,下面else中返回负数,便可。
} else if (m1.num == m2.num) {
return 0;
} else {
return 1;
}
}
});
//向集合中添加数据
ts.add(new M(5));
ts.add(new M(-3));
ts.add(new M(8));
ts.add(new M(6));
System.out.println(ts);
}
}
class M {
// 定义一个变量
int num;
public M(int num) {
// 构造函数中为变量赋值
this.num = num;
}
// 重写toString方法
public String toString() {
return "M对象num的值为" + this.num;
}
}
EnumSet类
EnumSet类是一个专为枚举类设计的集合类,EnumSet中全部的元素都必须是指定枚举类型的枚举值,该枚举类型在建立EnumSet时显式或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。EnumSet集合不容许插入null元素。
EnumSet集合的内部一位向量的形式存储,这种存储形式很是紧凑、高效,所以EnumSet对象占用内存很小,并且运行效率很好。具体体如今批量操做集合时。
EnumSet类没有暴露任何构造函数来建立该类的实例,程序经过它提供的static方法来建立EnumSet对象。
EnumSet集合经常使用的方法
(1)static EnumSet allOf(Class elementType):建立一个包含指定枚举类里全部枚举值的EnumSet集合。
(2)static EnumSet complementOf(EnumSet s):建立一个其元素类型与指定EnumSet里元素类型相同的EnumSet,新EnumSet集合包含原EnumSet集合所不包含的、此枚举类剩下的枚举值。
(3)static EnumSet copyOf(Collection c):使用一个普通集合来建立EnumSet集合。
(4)static EnumSet copyOf(EnumSet s):建立一个与指定EnumSet具备相同元素类型、相同集合元素的EnumSet。
(5)static EnumSet noneOf(Class elementType):建立一个元素类型为指定枚举类型的空EnumSet。
(6)static EnumSet of(E first,E...rest):建立一个包含一个或多个枚举值的EnunSet,传入的多个枚举值必须属于同一个枚举类。
(7)static EnumSet range(E from,E to):建立包含从from枚举值,到to枚举值范围内全部枚举值的EnumSet集合。
经典实例:
public class EnumSetTest {
public static void main(String[] args) {
EnumSet<Season> es=EnumSet.allOf(Season.class);
System.out.println(es);//打印[SPRING, SUMMER, FAILL, WINTER]
EnumSet<Season> es1=EnumSet.of(Season.SPRING,Season.SUMMER,Season.WINTER);
System.out.println(es1);//打印[SPRING, SUMMER, WINTER]
EnumSet<Season> es2=EnumSet.range(Season.SUMMER, Season.WINTER);
System.out.println(es2);//打印[SUMMER, FAILL, WINTER]
EnumSet<Season> es3=EnumSet.complementOf(es2);
System.out.println(es3);//打印[SPRING]
}
}
enum Season{
SPRING,SUMMER,FAILL,WINTER
}
总结
HashSet和TreeSet是Set的两个典型实现,HashSet的性能总比TreeSet好(添加,查询操做),由于TreeSet须要额外的红黑树算法来维护集合元素的次序。TreeSet是有序的集合。
HashSet还有一个子类LinkedHashSet,对于普通的插入,删除操做,LinkedHashSet比HashSet要慢一点点,这是由于维护链表所带来的开销。不过遍历集合时,LinkedHashSet就很是块 。
EnumSet是全部Set实现类中性能最好 ,但它只能保存同一个枚举类的枚举值做为集合元素。
注意:Set的三个实现类HashSet 、TreeSet、EnumSet都是线程不安全的。若是有多条线程同事访问一个Set集合,而且有超过一条线程修改集合的值,则必须手动保证集合的同步性,不然将没法访问修改后的集合。
List接口
List集合表明一个有序的集合 ,集合中每一个元素都有其对应的顺序索引。List集合容许使用重复元素,经过索引来访问指定位置的集合元素。
List集合在Collection的基础上新添加的方法:
(1)void add (int index,Object element):将元素element插入在List集合的index处。
(2)boolean addAll(int index,Collection c):将集合c所包含的全部元素都插入在List集合的Index处。
(3)Object get(int index):返回集合index索引处的元素。
(4)int indexOf(Object o):返回对象o在List集合中出现的位置索引。
(5)int lastIndexOf(Object o):返回对象o在List集合中最后一次出现的位置索引。
(6)Object remove(int index):删除并返回index索引处的元素。
(7)Object set(int index,Object element):将index索引处的元素替换成element对象,返回新元素。
(8)List subList(int fromIndex,int toIndex):返回从索引fromIndex(包含)到索引toIndex(不包含)处全部集合元素组成的子集合。
ListIterator接口:
ListIterator接口是Iterator的子接口,提供了专门操做List的方法。
ListIterator接口新增的方法:
(1)boolean hasPrevious():返回该迭代器关联的集合是否还有上一个元素。
(2)Object previous():返回该迭代器的上一个元素。
(3)void add():在指定位置插入一个元素。
根据上面的三个方法和解释,不难发现ListIterator新增长了向前迭代的功能,并且ListIterator还能够经过add方法向List集合中添加元素。
经典实例:
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("smarhit");
list.add("heima");
list.add("sichuan");
list.add("chengdu");
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
System.out.print(lit.next()+"\t");
}
System.out.println("\n----------开始反向迭代--------------");
while (lit.hasPrevious()) {
System.out.print(lit.previous()+"\t");
}
/*
* 打印的结果是:
* smarhit heima sichuan chengdu
* ----------开始反向迭代--------------
* chengdu sichuan heima smarhit
*/
}
}
ArrayList和Vector实现类
ArrayList和Vector类都是基于数组实现的List类,ArrayList和Vector类封装了一个动态在分配的Object[ ]数组。每一个ArrayList或Vector对象有一个capacity属性,该属性表示他们所封装的数组的长度,当想ArrayList或Vector中添加元素时,它们的capacity会自动增长。对于一般编程中,程序员无须关心ArrayList或Vector的capacity属性。但若是向ArrayList集合或Vector集合中添加大量元素时,可以使用ensureCapacity方法一次性的增长capacity。这样能够提升性能。
ArrayList和Vector在用法上几乎彻底相同(Vector是古老的集合,JDK1.0就存在了),但ArrayList集合是线程不安全的,当多条线程访问同一个集合时,若是有超过一条线程修改了ArrayList集合,则程序必须手动保证该集合的同步性。而Vector集合则是线程安全的。无须程序保证集合的同步性。因此Vector的性能比ArrayList的性能低。
Vector还提供了一个Stack子类,它用于模拟了“栈”这中数据结构,“栈”一般是指“后进先出”的容器。最后“push”进栈的元素,将最早被“pop”出栈。
Stack类提供的方法:
(1)Object peek():返回“栈”的第一个元素,但并不将该元素"pop"出栈。
(2)Object pop():返回"栈"的第一个元素,并将该元素"pop"出栈。
(3)void push(Object item):将一个元素“push”进栈,最后一个进“栈”的元素老是位于“栈”顶。
经典实例:
public class StackTest {
public static void main(String[] args) {
Stack<String> s=new Stack<String>();
s.push("smarhit");
s.push("beijin");
s.push("neijiang");
s.push("chengdu");
System.out.println(s);//打印[smarhit, beijin, neijiang, chengdu]
System.out.println(s.peek());//打印chengdu
System.out.println(s);//打印[smarhit, beijin, neijiang, chengdu]
System.out.println(s.pop());//打印chengdu
System.out.println(s);//打印[smarhit, beijin, neijiang]
}
}
固定长度的List
数组的工具类 Arrays提供的asList()方法是把一个数组或指定个数的对象转换成一个List集合, 但这个List集合既不是ArrayList实现类的实例,也不是Vector实现类的实例,而是Arrays的内部类ArrayList实例。Arrays.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合里的元素,不可增长,删除该集合中的元素。
Queue接口
Queue模拟了队列这中数据结构,队列一般是"先进先出"的容器。
Queue接口提供的方法:
(1)void add(Object e):将指定元素加入此队列的尾部。
(2)Object element():获取队列头部的元素,但不是删除该元素。
(3)boolean offer(Object e):将指定元素加入此队列的尾部。当使用有容器限制的队列时,此方法一般比add(Object e)方法更好。
(4)Object peek():获取队列头部的元素,可是不删除该元素。若是此队列为空,则返回null。
(5)Object poll():获取队列头部的元素,并删除该元素。若是此队列为空,则返回null。
(6)Object remove():获取队列头部元素,并删除该元素。
LinkedList实现类:
LinkedList类是一个比较特殊的类,它实现了List接口,还实现了Deque接口,Deque接口是Queue接口的子接口,它表明一个双向队列。
LinkedList类提供的方法:
(1)void addFirst(Object e):将指定元素插入该双向队列的开头。
(2)void addLast(Object e):将指定元素插入该双向队列的尾部。
(3)Iterator descendingIterator():返回以该双向队列对应的迭代器,该迭代器将以逆向顺序来迭代队列中的元素。
(4)Object getFirst():获取、但不删除双向队列的第一个元素。
(5)Object getLast():获取、但不删除双向队列的最后一个元素。
(6)boolean offerFirst(Object e):将指定的元素插入该双向队列的开头。
(7)boolean offerLast(Object e):将指定的元素插入该双向队列的尾部。
(8)Object peekFirst():获取、但不删除该双向队列的第一个元素;若是此双向队列为空,则返回null。
(9)Object peekLast():获取、但不删除该双向队列的最后一个元素;若是此双向队列为空,则返回null。
(10)Object pollFirst():获取、并删除该双向队列的第一个元素;若是此双向队列为空,则返回null。
(11)Object pollLast():获取、并删除该双向队列的最后一个元素;若是此双向队列为空,则返回null。
(12)Object pop():pop出该双向队列所表示的栈中第一个元素。
(13)void push(Object e):将一个元素push进该双向队列所表示的栈中。
(14)Object removeFirst():获取、并删除该双向队列的第一个元素。
(15)Object removeFirstOccurrence(Object o):删除该双向队列的第一个出现元素o。
(16)removeLast():获取、并删除该双向队列的最后一个元素。
(17)removeLastOccurrence(Object o):删除该双向队列的最后一次出现元素o。
总结:LinkedList与ArrayList、Vector的实现机制彻底不一样。ArrayList、Vector内部以数组的形式来保存集合中的元素,所以随机访问集合元素上有较好的性能;而linkedList内部以链表的形式来保存集合中的元素,所以随机方法集合元素时性能较差,但在插入、删除元素时性能很是出色(只需改变指针所指的地址便可)。
PriorityQueue实现类
PriorityQueue是一个比较标准的队列实现类,PriorityQueue保存队列元素的顺序并非按加入队列的顺序,而是按队列元素的大小进行从新排序。
PriorityQueue不容许插入null元素,它须要对队列元素进行排序。
排序的方式:天然排序,定制排序。
上面是对List集合的详解总结。在开发过程当中,咱们可能只运用到一些常见的结合,但其余集合也应作相应的了解。