1

Java Collections Framework是Java提供的对集合进行定义,操作,和管理的包含一组接口,类的体系结构。

Java集合框架的基本接口/类层次结构:

java.util.Collection [I]
+--java.util.List [I]
   +--java.util.ArrayList [C]
   +--java.util.LinkedList [C]
   +--java.util.Vector [C]
      +--java.util.Stack [C]
+--java.util.Set [I]
   +--java.util.HashSet [C]
   +--java.util.SortedSet [I]
      +--java.util.TreeSet [C]

java.util.Map [I]
+--java.util.SortedMap [I]
   +--java.util.TreeMap [C]
+--java.util.Hashtable [C]
+--java.util.HashMap [C]
+--java.util.LinkedHashMap [C]
+--java.util.WeakHashMap [C]

其中I表示接口,C表示实现类

1 List和Set

在实际开发中,需要将使用的对象存储于特定数据结构的容器中。JDK提供了这样的容器---集合(Collection)。Collection是一个接口,定义了集合相关的操作方法,其有两个子接口:List与Set

List:可重复集合
Set:不可重复的集合
其中判断元素是否重复,取决于元素的equals()比较的结果

2 集合持有对象的引用

集合中存储的都是引用类型元素,并且集合只保存每个元素对象的引用,而并非将元素对象本身存入集合。
图片描述

3 集合中常用的方法:

3.1 add方法

Collection定义了一个add方法用于向集合中添加新元素。
boolean add(E e)
该方法返会将给定的元素添加进集合,若添加成功,则返回true,否则返回false。

实例1

import java.util.ArrayList;
import java.util.Collection;
public class Test00{
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        System.out.println(c);
        c.add("a");
        c.add("b");
        c.add("c");
        System.out.println(c);
    }
}

3.2 contains方法

boolean contains(Object o)
该方法用于判定给定的元素是否被包含在集合中。若包含则返回true,反则返回false。
注意:集合在判断元素是否被包含在集合中是根据每个元素的equals方法进行比较的结果。
通常有必要重写equals()保证contains()方法的合理结果

实例2:

import java.util.ArrayList;
import java.util.Collection;
public class Test00{
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        System.out.println(c);
        c.add("a");
        c.add("b");
        c.add("c");
        System.out.println(c);
        Collection<String> b = new ArrayList<String>();
        b.add("b");
        b.add("c");
        System.out.println(c.contains(b));
        System.out.println(c.contains("b"));
        c.addAll(b);
        System.out.println(c);
        System.out.println(c.contains(b));
        System.out.println(c.contains("h"));
    }
}

3.3 size clear isEmpty

int size()
该方法用于返回当前集合中的元素总数
void clear()
该方法用于清空当前集合。
boolean isEmpty()
该方法用于判定当前集合中是否不包含任何元素

实例3 :

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class Test00{
    public static void main(String[] args) {
        Collection<String> c = new HashSet<String>();
        System.out.println(c.isEmpty());
        c.add("java");
        c.add("cpp");
        c.add("php");
        c.add("c#");
        c.add("cpp");
        System.out.println("isEmpty : " + c.isEmpty() + ",size : "+ c.size());
        c.clear();// 清空该集合
        System.out.println("isEmpty : "+ c.isEmpty() + ",size : " + c.size());
    }
}

addAll  containsAll
boolean addAll(Collection <? extends E> c)
该方法需要我们传入一个集合,并将该集合中的所有元素添加到当前集合中。
boolean containsAll(Collection<?> c)
该方法用于判定当前结合是否包含给定集合中的所有元素,若包含则返回true。

实例4

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class Test00{
    public static void main(String[] args) {
        Collection<String> c1 = new ArrayList<String>();
        c1.add("java");
        c1.add("cpp");
        c1.add("php");
        c1.add("c#");
        c1.add("objective-c");
        c1.add("cppc");
        System.out.println(c1);
        Collection<String> c2 = new HashSet<String>();
        c2.addAll(c1);
        System.out.println(c2);
        Collection<String> c3 =new ArrayList<String>();
        c3.add("java");
        c3.add("cpp");
        System.out.println(c1.containsAll(c3));
    }
}

4 Iterator

Iterator是迭代器,拥有两个方法

4.1 hasNext,next方法

迭代器用于遍历集合元素。获取迭代器可以使用Collection定义的方法:

Iterator iterator()

迭代器Iterator是一个借口,集合在重写Collection的iterator()方法时利用内部类提供了迭代器的实现。

Iterator提供了统一的遍历元素集合的方法,其提供了用于遍历集合的两个方法:
boolean hasNext():判断集合是否还有元素可以遍历
E next():返回迭代的下一个元素

实例4

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class Test00{
    public static void main(String[] args) {
        Collection<String> c = new HashSet<String>();
        c.add("java");
        c.add("cpp");
        c.add("php");
        c.add("c#");
        c.add("objective-c");
        Iterator<String> iterator = c.iterator();
        while(iterator.hasNext()){
            String str = iterator.next();
            System.out.println(str);
        }
    }
}

4.2 remove方法

在使用迭代器遍历集合时,不能通过集合的remove方法删除集合元素,否则会抛出并发更改异常。我们可以通过迭代器自身提供的remove()方法来删除通过next()迭代出的元素

void remove()

迭代器的删除方法是在原集合中删除元素。

这里需要注意的是:在调用remove方法前必须通过迭代器的next方法迭代过的元素,那么删除的就是这个元素。并且不能够再次调用remove方法,除非再次调用next()后方可再次调用。

实例5:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class Test00{
    public static void main(String[] args) {
        Collection<String> c = new HashSet<String>();
        c.add("java");
        c.add("cpp");
        c.add("php");
        c.add("c#");
        c.add("objective-c");
        Iterator<String> it = c.iterator();
        while(it.hasNext()){
            String str =  it.next();
            if(str.indexOf("c")!=-1){
                it.remove();// 删除包含字母c的元素
            }
        }
        System.out.println(c);
    }
}

4.3 增强型for循环

Java5.0之后推出了一个新的特性,增强for循环,也成为新循环。该循环不通用于传统循环的工作,其只用于遍历集合或数组。

语法:
for(元素类型 e:集合或数组){
   循环体
}

实例7

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class Test00{
    public static void main(String[] args) {
        Collection<String> c = new HashSet<String>();
        c.add("java");
        c.add("cpp");
        c.add("php");
        c.add("c#");
        c.add("objective-c");
        for(String str : c)
        {
            System.out.print(str.toUpperCase()+" ");
            //C# CPP OBJECTIVE-C JAVA PHP 
        }
    }
} 

新循环并非新的语法,而是在编译过程中,编译器会将新循环转为迭代器模式。所以新循环本质上是迭代器。

5 泛型机制

泛型是Java SE5.0引入的特性,泛型的本质是参数化类型。在类、接口、和方法的定义过程中,所操作的数据类型被传入的参数指定。

Java泛型机制广泛的应用在集合框架中。所有的集合类型都带有泛型的参数,这样在创建集合时可以指定放入集合中的元素的类型。Java编译器可以据此进行类型检查,这样可以减少代码在运行时出现错误的可能性。

图片描述

6 List

List接口是Collection的子接口,用于定义线性表数据结构。可以讲List理解为存放对象的数组,只不过其元素可以动态的增加或减少。
List接口的两个常见实现类为ArrayList和LinkList,分别用动态数组和链表的方式实现了List接口。
可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定差别。ArrayList更适合于随机访问,LinkList更适合于插入和删除。在性能要求不是特别苛刻的情形下可以忽略这个差别。

6.1 get和set

List除了继承Collection定义方法外,还根据其线性表的数据结构定义了一系列的方法,其中最常用的就是基于下标的get和set方法

E get(int index)
获取集合执行下标对应的元素,下标从0开始。
E set(int index,Element)
将给定的元素存入给定位置,并将原位置的元素返回。

实例8

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
public class Test00{
    public static void main(String[] args) {
        List<String> c = new ArrayList<String>();
        c.add("java");
        c.add("cpp");
        c.add("php");
        c.add("c#");
        c.add("objective-c");
        for(int i = 0;i<c.size();i++){
            System.out.println(c.get(i).toUpperCase());
        }
        String value = c.set(1, "c++");
        System.out.println(value);// cpp
        System.out.println(c);// [java, c++, php, c#, objective-c]
        c.set(1,c.set(3, c.get(1)));// 交换1和3上的元素位置  因为内层返回的是3位置的元素
        System.out.println(c);// [java, c#, php, c++, objective-c]
    }
}    

6.2 插入和删除

List根据下标的操作还支持插入语删除操作

void add(int index,Element);
将给定的元素插入到指定位置,原位置及后续元素都顺序向后移动。

E remove(int index);
删除给定位置的元素,并将被删除的元素返回。

6.3 List转换为数组

List的toArray方法用于将集合转换为数组。但实际上该方法是在Collection中定义的,所以所有的集合都具备这个功能。

其有两个方法:
Object[] toArray()
<T>T[] toArray(T[] a)

其中第二个方法是比较常用的,我们可以传入一个指定类型的数组,该数组的元素类型与集合的元素类型一致。返回值则是转换后的数组,该数组会保存集合中的所有元素。

6.4 数组转换为List

Arrays类中提供了一个静态方法asList,使用该方法我们可以将一个数组转换为对应的List集合。
其方法定义为:

static <T>List<T> asList<T... a>

返回的List的集合元素类型由传入的数组的元素类型决定。
并且要注意的是,返回的集合我们不能对其增删元素。并且对集合的元素进行修改hi影响数组对应的元素。

6.5 List排序

Collection.sort方法实现排序
Collection是集合的工具类,它提供了很多便于我们操作集合的方法,其中就有用于集合排序的sort方法。该方法定义为:

void sort(List<T> list)
该方法的作用是对给定的集合元素进行自然排序。

6.6 Comparable

Collection的sort方法是对集合元素进行自然排序,那么两个元素对象之间就一定要有大小之分。这个代销之分是如何界定的?

实际上,在使用Collection的sort排序的结合都必须是Comparable接口实现类,该接口表示其子类是可比较的,因为实现该接口必须重写抽象方法:

int compareTo(T t);
该方法返回值要求:
若o1>o2则返回值应>0
若o1<o2则返回值应<0
若o1=o2则返回值因为0

6.7 LinkedList

双向链表
    双端效率高

方法

add(数据)    添加数据
get(i)        访问指定位置的收
remove(i)     移除指定位置的数据
size()        元素的数量
addFirst()    在链表首处添加元素
addLast()    在链表末尾添加元素
getFirst()    获得第一个元素
getLast()    获得末尾元素
removeFirst()    删除第一个元素
removeLast()    删除最后一个元素
iterator()
    辅助创建迭代器对象进行设置

LinkedList实例:

    import java.lang.reflect.Array;
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.Queue;
    
    public class Test00{
        public static void main(String[] args) {
            LinkedList<String> list = new LinkedList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
            list.add("ddd");
            list.add("eee");
            list.add("fff");
            list.add("ggg");
            list.add("hhh");
            list.add("iii");
            list.add("jjj");
            list.add("kkk");
            list.add("lll");
                
            System.out.println("获取链表数组的大小: "+list.size());// 获取链表的大小
            System.out.println("get方法获取元素 "+list.get(0));
            System.out.println("获取第一个元素"+list.getFirst());
            System.out.println("获取链表的之后一个元素 "+list.getLast());
            
            LinkedList<String> list1 = new LinkedList<>();
            list1.addAll(list);
            for(String s1:list1){// 元素遍历
                System.out.println(s1);
            }
             // 通过迭代器来遍历
            Iterator<String> iterator = list.iterator();
            
            if(iterator.hasNext()){
                String str = iterator.next();
                System.out.println(str);
            }
            
            System.out.println("删除链表的第一个元素 "+list.removeFirst());
            System.out.println("删除链表的最后一个元素: "+list.removeLast());
            System.out.println("找到第一个相等的元素进行删除  "+list.remove("ddd"));
            System.out.println("指定删除链表中的某个元素:"+list.remove(4));
            System.out.println(list.toArray());// 将list链表转为数组
            Object[] listarr = list.toArray();// 将list转为数组,并利用数组的方式进行答应
            System.out.println(Arrays.toString(listarr));
        }
    }

6.8 ArrayList和LinkedList的大致区别如下:

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据  

示例如下:


import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class Test00{
    static final int N = 500000;
    static long timeList(List list){
        long start = System.currentTimeMillis();
        Object o = new Object();
        for(int i = 0;i<N;i++){
            list.add(0,o);
        }
        return System.currentTimeMillis() - start;
        
    }
    
    static long readList(List list){
        long start = System.currentTimeMillis();
        for(int i = 0;i<list.size();i++){
            
        }
        return System.currentTimeMillis() - start;
        
    }
    
    static List addList(List list){
        Object o = new Object();
        for(int i = 0;i<N;i++){
            list.add(0,o);
        }
        return list;
    }
    
    public static void main(String[] args) {
        System.out.println("ArrayList添加"+N+"条耗时:"+timeList(new ArrayList()));
        System.out.println("LinkedList添加"+N+"条耗时"+timeList(new LinkedList()));
        
        List list1 = addList(new ArrayList());
        List list2 = addList(new LinkedList());
        System.out.println("ArrayList查找"+N+"条耗时"+readList(list1));
        System.out.println("LinkedList查找"+N+"条记录耗时"+timeList(list2));
        /*   结果如下
             ArrayList添加500000条耗时:31141
            LinkedList添加500000条耗时1
            ArrayList查找500000条耗时15
            LinkedList查找500000条记录耗时3
         */
        
    }
}

7 队列和栈

7.1 Queue(队列)

队列是常用的数据结构,可以将队列看成特殊的线性表,队列限制了线性表的访问方式:只能从线性表
的一端添加(offer)元素,从另一端取出(poll)元素。

队列遵循先进先出(FIFO First Input First Output)的原则。

JDK中提供了Queue接口,同时使用LinkedList实现了该接口(选择LinkList实现Queue的原因在于
Queue经常要进行添加和删除的操作,而LinkList在这方面效率较高)。

Queue接口中主要方法如下:

boolean off(E e)     将一个元素添加至队尾,如果添加成功则返回true。
E poll()             从队首删除并返回一个元素。
E peek()            返回队首的元素(但并不删除).

7.2 Deque

Deque是Queue的子接口,定义了所谓的"双端队列",即从队列的两端分别可以入队(offer)和出队(poll),LinkList实现了该接口。
如果将Deque限制为只能从一端入队和出队,则可实现"栈"(Stack)数据结构,对栈而言,入栈称之为push,出栈称之为pop。
栈遵循先进后出(FILO First Input Last Output)的原则。
图片描述


import java.util.LinkedList;
import java.util.Queue;
public class Test00{
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<String>();
        queue.offer("a");// 将一个对象添加至队尾,如果添加成功则返回true
        queue.offer("b");
        queue.offer("c");
        System.out.println(queue);
        String str =queue.peek();
        System.out.println(str);
        while(queue.size()>0){
            // 从队首删除并返回一个元素
            str  = queue.poll();
            System.out.println(str + " ");
        }
        
    }
}

文章参考:http://blog.sina.com.cn/s/blo...


天月
11 声望0 粉丝