Java集合框架

2019-03-26  本文已影响0人  bo132
一.集合框架主要接口
No 接口 说明
1 Collection Collection 是层次结构 中的根接口。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
2 List Collection接口的子接口。List存储的元素允许重复。
3 Set Collection接口的子接口。Set存储的元素不允许重复。
4 Map 存放键值对的接口,接口中的每个元素以key—value形式存储。
5 Queue 队列接口,此接口的子类可以实现队列操作
6 Iterator 集合的输出接口,用于输出集合中的内容,只能从前到后的单向输出
7 SortedSet 单值的排序接口,实现接口的集合类,里面的元素使用比较器排序
8 SortedMap 键值对集合的排序接口,里面的元素按照key排序

二. 集合框架对数据结构的应用

1.简介
  在Java语言中,Java的设计者对常用的的数据结构和算法进行一系列的规范(接口)和类(类),所有抽象出来的数据结构和操作(算法)统称为Java集合框架。Java程序员在具体应用的时候,不必考虑数据结构和算法的实现细节,只需要使用具体的类便可以解决问题,大大提高了编程效率。这些数据结构在 java.util 包里,包含了 Collection、List、Set、Map、SortedMap 接口。这些接口的实现类有 LinkedList、TreeSet、ArrayList、HashMap 等。


2.分类


3.优点


4.缺点


三.Java集合框架接口详细介绍

1.Collection接口
  Collection是最基本的接口。一个Collection代表一组Object对象。Java不提供直接继承自Collection的类,Java提供的类都是继承子Collection的子类接口。例如List和Set。
  所有实现Collection的类都必须提供两个构造函数,一个无参的构造用于创建空的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。
  不论Collection的实际类型如何,他都支持一个iterator()方法,该方法返回一个迭代子,使用该迭代子可逐一访问集合中的每一个元素。
  Collection接口派生的两个接口是List和Set。


2.List
  List是一个有序的Collection接口,类似c语言的数组,使用该接口能够准确控制每个元素插入的位置。可以通过索引来访问List的每个元素。
  和Set不同的是,List可以插入相同的元素,而Set中不可以出现重复的元素。
  除了Collection的Iterator的接口,List还实现了listIterator()接口,多了增加,删除,修改向前向后遍历。
  实现List接口的常用类有LinkedList,ArrayList,Vector,Stack。


2.1.LinkedList
  LinkedList实现了List接口,允许null元素。LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:

Listlist=Collections.synchronizedList(newLinkedList(...));
参考资料

import java.util.List;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;

public class LinkedListTest {
    public static void main(String[] args) {
        // 测试LinkedList的API
        testLinkedListAPIs() ;

        // 将LinkedList当作 LIFO(后进先出)的堆栈
        useLinkedListAsLIFO();

        // 将LinkedList当作 FIFO(先进先出)的队列
        useLinkedListAsFIFO();
    }
    
    /*
     * 测试LinkedList中部分API
     */
    private static void testLinkedListAPIs() {
        String val = null;
        //LinkedList llist;
        //llist.offer("10");
        // 新建一个LinkedList
        LinkedList llist = new LinkedList();
        //---- 添加操作 ----
        // 依次添加1,2,3
        llist.add("1");
        llist.add("2");
        llist.add("3");

        // 将“4”添加到第一个位置
        llist.add(1, "4");
        

        System.out.println("\nTest \"addFirst(), removeFirst(), getFirst()\"");
        // (01) 将“10”添加到第一个位置。  失败的话,抛出异常!
        llist.addFirst("10");
        System.out.println("llist:"+llist);
        // (02) 将第一个元素删除。        失败的话,抛出异常!
        System.out.println("llist.removeFirst():"+llist.removeFirst());
        System.out.println("llist:"+llist);
        // (03) 获取第一个元素。          失败的话,抛出异常!
        System.out.println("llist.getFirst():"+llist.getFirst());


        System.out.println("\nTest \"offerFirst(), pollFirst(), peekFirst()\"");
        // (01) 将“10”添加到第一个位置。  返回true。
        llist.offerFirst("10");
        System.out.println("llist:"+llist);
        // (02) 将第一个元素删除。        失败的话,返回null。
        System.out.println("llist.pollFirst():"+llist.pollFirst());
        System.out.println("llist:"+llist);
        // (03) 获取第一个元素。          失败的话,返回null。
        System.out.println("llist.peekFirst():"+llist.peekFirst());
    

        System.out.println("\nTest \"addLast(), removeLast(), getLast()\"");
        // (01) 将“20”添加到最后一个位置。  失败的话,抛出异常!
        llist.addLast("20");
        System.out.println("llist:"+llist);
        // (02) 将最后一个元素删除。        失败的话,抛出异常!
        System.out.println("llist.removeLast():"+llist.removeLast());
        System.out.println("llist:"+llist);
        // (03) 获取最后一个元素。          失败的话,抛出异常!
        System.out.println("llist.getLast():"+llist.getLast());


        System.out.println("\nTest \"offerLast(), pollLast(), peekLast()\"");
        // (01) 将“20”添加到第一个位置。  返回true。
        llist.offerLast("20");
        System.out.println("llist:"+llist);
        // (02) 将第一个元素删除。        失败的话,返回null。
        System.out.println("llist.pollLast():"+llist.pollLast());
        System.out.println("llist:"+llist);
        // (03) 获取第一个元素。          失败的话,返回null。
        System.out.println("llist.peekLast():"+llist.peekLast());

         

        // 将第3个元素设置300。不建议在LinkedList中使用此操作,因为效率低!
        llist.set(2, "300");
        // 获取第3个元素。不建议在LinkedList中使用此操作,因为效率低!
        System.out.println("\nget(3):"+llist.get(2));


        // ---- toArray(T[] a) ----
        // 将LinkedList转行为数组
        String[] arr = (String[])llist.toArray(new String[0]);
        for (String str:arr) 
            System.out.println("str:"+str);

        // 输出大小
        System.out.println("size:"+llist.size());
        // 清空LinkedList
        llist.clear();
        // 判断LinkedList是否为空
        System.out.println("isEmpty():"+llist.isEmpty()+"\n");

    }

    /**
     * 将LinkedList当作 LIFO(后进先出)的堆栈
     */
    private static void useLinkedListAsLIFO() {
        System.out.println("\nuseLinkedListAsLIFO");
        // 新建一个LinkedList
        LinkedList stack = new LinkedList();

        // 将1,2,3,4添加到堆栈中
        stack.push("1");
        stack.push("2");
        stack.push("3");
        stack.push("4");
        // 打印“栈”
        System.out.println("stack:"+stack);

        // 删除“栈顶元素”
        System.out.println("stack.pop():"+stack.pop());
        
        // 取出“栈顶元素”
        System.out.println("stack.peek():"+stack.peek());

        // 打印“栈”
        System.out.println("stack:"+stack);
    }

    /**
     * 将LinkedList当作 FIFO(先进先出)的队列
     */
    private static void useLinkedListAsFIFO() {
        System.out.println("\nuseLinkedListAsFIFO");
        // 新建一个LinkedList
        LinkedList queue = new LinkedList();

        // 将10,20,30,40添加到队列。每次都是插入到末尾
        queue.add("10");
        queue.add("20");
        queue.add("30");
        queue.add("40");
        // 打印“队列”
        System.out.println("queue:"+queue);

        // 删除(队列的第一个元素)
        System.out.println("queue.remove():"+queue.remove());
    
        // 读取(队列的第一个元素)
        System.out.println("queue.element():"+queue.element());

        // 打印“队列”
        System.out.println("queue:"+queue);
    }
}

运行结果:


Test "addFirst(), removeFirst(), getFirst()"
llist:[10, 1, 4, 2, 3]
llist.removeFirst():10
llist:[1, 4, 2, 3]
llist.getFirst():1

Test "offerFirst(), pollFirst(), peekFirst()"
llist:[10, 1, 4, 2, 3]
llist.pollFirst():10
llist:[1, 4, 2, 3]
llist.peekFirst():1

Test "addLast(), removeLast(), getLast()"
llist:[1, 4, 2, 3, 20]
llist.removeLast():20
llist:[1, 4, 2, 3]
llist.getLast():3

Test "offerLast(), pollLast(), peekLast()"
llist:[1, 4, 2, 3, 20]
llist.pollLast():20
llist:[1, 4, 2, 3]
llist.peekLast():3

get(3):300
str:1
str:4
str:300
str:3
size:4
isEmpty():true


useLinkedListAsLIFO
stack:[4, 3, 2, 1]
stack.pop():4
stack.peek():3
stack:[3, 2, 1]

useLinkedListAsFIFO
queue:[10, 20, 30, 40]
queue.remove():10
queue.element():20
queue:[20, 30, 40]


2.2.ArrayList
  ArrayList实现了可变大小的数组,允许添加null。ArrayList是非同步的(unsynchronized)。每个ArrayList有一个容量大小,当元素不断增加到ArrayList里面时,容量随着元素的添加自动增加,由于每次增加元素判断增加长度会消耗时间,所以插入前我们可以调用ensureCapacity方法来增加ArrayList的容量,以便提高效率。

ublic class ArrayListTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        
        list.add("Apple");
        list.add("Watermelon");
        list.add("Banana");
        list.add("Strawbarry");
        // for循环遍历打印输出
        for(String s : list) {
            System.out.println(s);
        }
        
        // 将ArrayList转化为数组,遍历打印
        String[] stringArrays = new String[list.size()];
        list.toArray(stringArrays);
        for(int i = 0; i<stringArrays.length;i++) {
            System.out.println(stringArrays[i]);
        }
        
        // 使用迭代器遍历
        Iterator<String> it = list.iterator();
        while(it.hasNext()) {
            System.out.println(it.next());
        }
        
        final int N=1000000;
        ArrayList<String> list1 = new ArrayList<String>();
        long start = System.currentTimeMillis();
        for(int i=0;i<N;i++) {
            list1.add("1");
        }
        System.out.println(System.currentTimeMillis()-start);
        
        ArrayList<String> list2 = new ArrayList<String>();
        long start2 = System.currentTimeMillis();
        list2.ensureCapacity(N); // 对ArrayList进行扩充
        for(int i=0;i<N;i++) {
            list2.add("1");
        }
        System.out.println(System.currentTimeMillis()-start2); // 执行结果比原先快18ms
    }
}

2.3.Vector
  Vector与ArrayList类似,不同的是Vector是同步的,允许重复元素,底层数据结构可变数组,由于线程问题,ArrayList检索的效率高于Vector。


2.4.Stack
  Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。


3.Set
  Set接口没有提供Collection 接口额外的方法,但实现Set接口的集合类中的元素是不可重复的。所以Set添加的元素必须定义equals()方法以确保对象的唯一性。Set接口不保证维护元素的次序。
   Set的实现类主要有:HashSet及其子类 LinkedHashSet

package HashSetTest;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class HashSet {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<String,String>();
        map.put("1","value1");
        map.put("2","value2");
        // map 再put的话 会更新2的value
        map.put("2", "good");
        map.put("3","value3");
        
        //第一种,普遍使用
        System.out.println("通过Map.keySet遍历key何value:");
        for(String key :map.keySet()) {
            System.out.println("key=" + key + " and value= " + map.get(key));
        }
        
        // 通过Map.entrySet使用iterator遍历key和value
        System.out.println("通过Map.entrySet使用iterator遍历key和value:");
        Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); 
        while(it.hasNext()) {
            Map.Entry<String, String> enter = it.next();
            System.out.println("key= " + enter.getKey() + "value= " + enter.getValue());
        
        }
        //第三种:推荐,尤其是容量大时
         System.out.println("通过Map.entrySet遍历key和value");
        for(Map.Entry<String, String> entry:map.entrySet()) {
            System.out.println("key= " + entry.getKey() + "vaue= " + entry.getValue());
        }
        
        //第四种
        System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
        for(String v : map.values()) {
            System.out.println("value: "+v);
        }
        
    }
}

参考资料

a)(在对大量信息进行检索的时候,TreeSet比AraayList更有效率,能保证在log(n)的时间内完成)。

b)TreeSet是实用树形结构来存储信息的,每个节点都会保存一下指针对象,分别指向父节点,左分支,右分支,相比较而言,ArrayList就是一个含有元素的简单数组了,正因为如此,它占的内存也要比ArrayList多一些。

c)想TreeSet插入元素也比ArrayList要快一些,因为当元素插入到ArrayList的任意位置时,平均每次要移动一半的列表,需要O(n)的时间, 而TreeSet深度遍历查询花费的实施只需要O(log(n))(普遍的都是,set查询慢,插入快,list查询快,插入满。)


4.Map
  Map接口有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap,Map存储键值对,不允许键重复,允许值重复,允许值重复。


5.Queue
Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Deque接口。基本上,一个队列就是一个先入先出(FIFO)的数据结构。
详细解释


6.Collection
Collections是针对集合类的一个帮助类。提供了一系列静态方法实现对各种集合的搜索、排序、线程完全化等操作。

最常用的是ArrayList,HashSet,HashMap,Array。TreeXXX用于排序的比较多。底层实现

上一篇下一篇

猜你喜欢

热点阅读