List集合知识总结

转载: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集合的详解总结。在开发过程当中,咱们可能只运用到一些常见的结合,但其余集合也应作相应的了解。