JAVA集合体系

来源:互联网 发布:数据有效性输入信息 编辑:程序博客网 时间:2024/05/29 11:16

集合框架体系示意图

1

一、List结构的集合类
1、ArrayList
1-1、如何使用

  ArrayList al = new ArrayList();        al.add("1");        al.add("3");        al.add("2");        for (int i = 0; i < al.size(); i++) {            System.out.println(al.get(i));        }

输出结果:
1
3
2

2、LinkedList
2-1、如何使用

LinkedList ll = new LinkedList();        ll.add("1");        ll.add("3");        ll.add("2");        for (int i = 0; i < ll.size(); i++) {            System.out.println(ll.get(i));        }

输出结果:
1
3
2

2-2、ArrayList和LinkedList性能对比

package com.collection;import java.util.ArrayList;import java.util.LinkedList;import java.util.List;public class TestMain {    static final int N = 50000;    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) + "毫秒");    }    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, j = list.size(); i < j; 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;    }}

输出结果:
ArrayList添加50000条耗时:212毫秒
LinkedList添加50000条耗时:7毫秒
ArrayList查找50000条耗时:1毫秒
LinkedList查找50000条耗时:6毫秒

显然我们可以看出ArrayList更适合读取数据,linkedList更多的时候添加或删除数据。

2-3、ArrayList和LinkedList的大致区别

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

2-4、ArrayList和LinkedList的适用场景

1.对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
2.在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
3.LinkedList不支持高效的随机元素访问。
4.ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
简单说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。

3、Vector
3-1、如何使用

Vector   vv=new Vector();        vv.add("1");        vv.add("3");        vv.add("2");        for (int i = 0; i < vv.size(); i++) {            System.out.println(vv.get(i));        }

输出结果:
1
3
2

3-2、Vector 和 ArrayList 性能对比

package com.collection;import java.util.ArrayList;import java.util.List;import java.util.Vector;public class TestMain {    static final int N = 50000;    public static void main(String[] args) {        System.out.println("ArrayList添加" + N + "条耗时:"                + timeList(new ArrayList()) + "毫秒");        System.out.println("Vector添加" + N + "条耗时:" + timeList(new Vector())                + "毫秒");        List list1 = addList(new ArrayList<>());        List list2 = addList(new Vector());        System.out.println("ArrayList查找" + N + "条耗时:" + readList(list1) + "毫秒");        System.out.println("Vector查找" + N + "条耗时:" + timeList(list2) + "毫秒");    }    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, j = list.size(); i < j; 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;    }}

输出结果:
ArrayList添加50000条耗时:216毫秒
Vector添加50000条耗时:211毫秒
ArrayList查找50000条耗时:1毫秒
Vector查找50000条耗时:745毫秒

3-3、Vector与ArrayList区别

1、Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。
2、当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。

4、Stack
4-1、如何使用

package com.collection;import java.util.Enumeration;import java.util.Stack;public class TestMain {    public static void main(String[] args) {        Stack stack = new Stack(); // 创建堆栈对象        System.out.println("11111, absdder, 29999.3 三个元素入栈");        stack.push(new Integer(11111)); // 向 栈中 压入整数 11111        printStack(stack); // 显示栈中的所有元素        stack.push("absdder"); // 向 栈中 压入        printStack(stack); // 显示栈中的所有元素        stack.push(new Double(29999.3)); // 向 栈中 压入        printStack(stack); // 显示栈中的所有元素        String s = new String("absdder");        System.out.println("元素absdder在堆栈的位置" + stack.search(s));        System.out.println("元素11111在堆栈的位置" + stack.search(11111));        System.out.println("11111, absdder, 29999.3 三个元素出栈"); // 弹出 栈顶元素        System.out.println("元素" + stack.pop() + "出栈");        printStack(stack); // 显示栈中的所有元素        System.out.println("元素" + stack.pop() + "出栈");        printStack(stack); // 显示栈中的所有元素        System.out.println("元素" + stack.pop() + "出栈");        printStack(stack); // 显示栈中的所有元素    }    private static void printStack(Stack<Integer> stack) {        if (stack.empty())            System.out.println("堆栈是空的,没有元素");        else {            System.out.print("堆栈中的元素:");            Enumeration items = stack.elements(); // 得到 stack 中的枚举对象            while (items.hasMoreElements())                // 显示枚举(stack ) 中的所有元素                System.out.print(items.nextElement() + " ");        }        System.out.println(); // 换行    }}

输出结果:
11111, absdder, 29999.3 三个元素入栈
堆栈中的元素:11111
堆栈中的元素:11111 absdder
堆栈中的元素:11111 absdder 29999.3
元素absdder在堆栈的位置2
元素11111在堆栈的位置3
11111, absdder, 29999.3 三个元素出栈
元素29999.3出栈
堆栈中的元素:11111 absdder
元素absdder出栈
堆栈中的元素:11111
元素11111出栈
堆栈是空的,没有元素

栈的特性

1、栈的最主要特性就是后进先出
2、栈是限制再表尾进行插入和删除操作的线性表,允许插入、删除的这一端称为栈顶,另一端为栈底,栈是软件设计中常用的一种数据结构。

又因为JAVA中Stack 继承自 Vector,所以可以使用Vector的public和protected的方法

Stack stack = new Stack();        stack.push("1");        stack.push("3");        stack.push("2");        for (int i = 0; i < stack.size(); i++) {            System.out.println(stack.get(i));        }

输出结果:
1
3
2

二、Set结构的集合类

1、HashSet

1-1、HashSet的用法

package com.collection;import java.util.HashSet;import java.util.Iterator;import java.util.Set;public class TestMain {    public static void main(String[] args) {        Set set = new HashSet();        String s1 = new String("hello");        String s2 = s1;        String s3 = new String("world");        set.add(s1);        set.add(s2);        set.add(s3);        System.out.println("Set的个数:" + set.size());        Iterator iterator = set.iterator();        while (iterator.hasNext()) {            System.out.println("value=" + iterator.next().toString());        }    }}

输出结果:
Set的个数:2
value=world
value=hello

例子2:

package com.collection;import java.util.ArrayList;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Set;public class TestMain {    public static void main(String[] args) {        Set set = new HashSet();        set.add("abc");        set.add("cde");        set.add("efg");        set.add("fgh");        set.add("abc"); // 重复的abc,set会自动将其去掉        System.out.println("size1=" + set.size());        List list = new ArrayList();        list.add("abc");        list.add("aaa");        list.add("fff");        set.addAll(list); // 将list中的值加入set,并去掉重复的abc        System.out.println("size2=" + set.size());        for (Iterator it = set.iterator(); it.hasNext();) {            System.out.println("value=" + it.next().toString());        }    }}

输出结果:
size1=4
size2=6
value=aaa
value=abc
value=cde
value=fgh
value=efg
value=fff

1-2、 Set的特性

1、Set具有与Collection完全一样的接口,因此没有任何额外的功能,不像前面有两个不同的List。实际上Set就是Collection,只是行为不同。(这是继承与多态思想的典型应用:表现不同的行为。)Set不保存重复的元素(至于如何判断元素相同则较为负责)
2、Set : 存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。

1-3、HashSet与上面 ArrayList的比较

1、为快速查找设计的Set。存入HashSet的对象必须定义hashCode();
2、 ArrayList可以重复添加元素、HashSet不保存重复元素。

2、TreeSet
2-1、TreeSet的用法:

package com.collection;import java.util.Iterator;import java.util.Set;import java.util.TreeSet;public class TestMain {    public static void main(String[] args) {        Set<String> set = new TreeSet<String>();        set.add("abc");        set.add("xyz");        set.add("rst");        System.out.println(set);// 可以直接输出        Iterator itSet = set.iterator();// 也可以遍历输出        while (itSet.hasNext())            System.out.print(itSet.next() + "\t");    }}

输出结果:
[abc, rst, xyz]
abc rst xyz

2-2、TreeSet的特性

1、 保存次序的Set, 底层为树结构(二叉树)。使用它可以从Set中提取有序的序列。

三、Map结构的集合类

1、HashMap
1-1、HashMap的使用方法

public class MyTest {    public static void main(String[] args) {        HashMap hm = new HashMap();        hm.put("a", "1");        hm.put("b", "2");        hm.put("c", "3");        // 遍历 HashMap中所以的key和value        // Iterator迭代器        Iterator it = hm.keySet().iterator();        // hasNext()<->还有没有下一个,返回一个boolean        while (it.hasNext()) {            // 取出key;key设的字符串类型;it.next()返回的是一个object,所以toString            String key = it.next().toString();            // 通过key 取出value            String value = (String) hm.get(key);            System.out.println(value);        }    }}

输出结果:
2
3
1

例子2

public class MyTest {    public static void main(String[] args) {        HashMap hm = new HashMap();        hm.put("a", "1");        hm.put("b", "2");        hm.put("c", "3");        hm.put(null, "4");        hm.put(null, null);        System.out.println(hm.get(null));    }}

输出结果:
null

2、 Hashtable

1、 Hashtable的使用方法

public class MyTest {    public static void main(String[] args) {        Hashtable hm = new Hashtable();        hm.put("a", "1");        hm.put("b", "2");        hm.put("c", "3");        // 遍历Hashtable中所以的key和value        // Iterator迭代器        Iterator it = hm.keySet().iterator();        // hasNext()<->还有没有下一个,返回一个boolean        while (it.hasNext()) {            // 取出key;key设的字符串类型;it.next()返回的是一个object,所以toString            String key = it.next().toString();            // 通过key 取出value            String value = (String) hm.get(key);            System.out.println(value);        }    }}

输出结果:
2
1
3

例子2

这里写图片描述

1-2、HashMap和Hashtable区别
1、父类不一样
public class java.util.Hashtable extends java.util.Dictionary implements java.util.Map, java.lang.Cloneable, java.io.Serializable
public class java.util.HashMap extends java.util.AbstractMap implements java.util.Map, java.lang.Cloneable, java.io.Serializable

HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口。

Hashtable 有一个 contains方法,容易引起误会,所以在HashMap里面已经去掉了。当然,2个类都用containsKey和containsValue方法。

2、主要区别
a、HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
b、HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
c、HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
d、Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
e、最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。
f、Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异

3、LinkedHashMap和HashMap的比较使用

3-1、代码如下:

public class MyTest {    public static void main(String[] args) {        System.out                .println("*************************LinkedHashMap*************");        Map<Integer, String> map = new LinkedHashMap<Integer, String>();        map.put(6, "apple");        map.put(3, "banana");        map.put(2, "pear");        for (Iterator it = map.keySet().iterator(); it.hasNext();) {            Object key = it.next();            System.out.println(key + "=" + map.get(key));        }        System.out.println("*************************HashMap*************");        Map<Integer, String> map1 = new HashMap<Integer, String>();        map1.put(6, "apple");        map1.put(3, "banana");        map1.put(2, "pear");        for (Iterator it = map1.keySet().iterator(); it.hasNext();) {            Object key = it.next();            System.out.println(key + "=" + map1.get(key));        }    }}

输出结果:
********************LinkedHashMap********
6=apple
3=banana
2=pear
********************HashMap********
2=pear
3=banana
6=apple

3-2、主要区别
1、LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
2、LinkedHashmap 的特点是put进去的对象位置未发生变化,而HashMap会发生变化.
3、LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。

四、Queue结构的集合
4-1、Queue使用方法

public class TestMain {    public static void main(String[] args) {        Queue<String> queue = new LinkedList<String>();        // 添加元素        queue.offer("a");        queue.offer("b");        queue.offer("c");        System.out.println("个数为:" + queue.size());        for (String q : queue) {            System.out.println(q);        }        System.out.println("**************************");        System.out.println("poll=" + queue.poll()); // 返回第一个元素,并在队列中删除        for (String q : queue) {            System.out.println(q);        }        System.out.println("个数为:" + queue.size());        System.out.println("**************************");        System.out.println("element=" + queue.element()); // 返回第一个元素        for (String q : queue) {            System.out.println(q);        }        System.out.println("**************************");        System.out.println("peek=" + queue.peek()); // 返回第一个元素        for (String q : queue) {            System.out.println(q);        }        System.out.println("个数为:" + queue.size());    }}

输出结果:
个数为:3
a
b
c


poll=a
b
c
个数为:2


element=b
b
c


peek=b
b
c
个数为:2

4-2、Queue特性

1、队列的主要特征就是”先进先出”。
2、队列是限制在两端进行插入和删除操作的线性表。能够插入元素的一端称为队尾,允许删除元素的一端称为队首。

4-3、Queue补充说明

在java5中新增加了java.util.Queue接口,用以支持队列的常见操作。Queue接口与List、Set同一级别,都是继承了Collection接口。
Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优
点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常。 如果要使用前端而不移出该元素,使用
element()或者peek()方法。
上文的LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。

LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。BlockingQueue 继承了Queue接口