前言:JAVA集合框架是JAVA编程中一个很重要的框架,在面试和开发中也会经常接触到,为了增强对集合框架的理解,特地在空余时间进行了总结。

 

一、集合框架的大体结构

java gui框架 java框架总结_数据

二、详解主要类及接口 

1.Collection接口

  • 集合框架的顶级框架(不是Iterator)
  • 是List和Set的父接口(List和Set一些公共的属性和方法放到了父类接口中)
  • 但不是Map的父类

2.List接口

  • 特点:有序,对象可以重复
  • 遍历方式:

List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("a");
        list.add("c");

//1.下标(for循环)
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

//2.foreach  jdk>=1.5才有的for循环增强版foreach  
        for (String s : list) {
            System.out.println(s);
        }

//3.Iterator迭代器(hasNext/next/remove)  it拿到迭代器对象,拿到对象要new,new 就需要调构造方法,构造方法也是方法
        //.iterator()方法是从List父亲Collection继承来的,既然是从父类继承,那么父类的方法返回一个迭代器
        //那么就意味一件事,在父类Collection的iterator()方法中,实例化了一个迭代器对象,所以说父类依赖于Iterator
        Iterator<String> it = list.iterator();
        Object v = null;
        //把it想象成从-1开始,实际上没有-1位置
        while(it.hasNext()) {//有没有下一个
            v = it.next();//移动下一个
            System.out.println(v);
            /**如果遍历List集合时又想删除其中的元素,请使用迭代器
            it.remove();//删除当前的元素v
            */
        }

//4.forEach  jdk>=1.8
        list.forEach(cc -> System.out.println(cc));//Lambda表达式(jdk>=1.8),表达式由三部分组成:参数列表,箭头(→),一个表达式或语句块。

 

/*其所有遍历的结果都是 
        a
        b
        a
        c                               */

新增内容:

        ListIterator listIterator = list.listIterator();//迭代器,继承Iterator
        while (listIterator.hasNext()) {//向前遍历
            Object object = (Object) listIterator.next();
            System.out.println(object);
        }
        System.out.println("xxxxxxxxxxxxx");
        while (listIterator.hasPrevious()) {//向后遍历
            Object object = (Object) listIterator.previous();
            System.out.println(object);
        }

/*其遍历的结果是 
       a
       b
       c
       d
       e
       xxxxxxxxxxxxx
       e
       d
       c
       b
       a                               */

如果直接使用向后遍历:

        ListIterator listIterator = list.listIterator();
        System.out.println("xxxxxxxxxxxxx");
        while (listIterator.hasPrevious()) {
            Object object = (Object) listIterator.previous();
            System.out.println(object);
        }

/*其遍历的结果是 
       xxxxxxxxxxxxx                         */

<ListIterator可向前向后遍历,list依赖于ListIterator,所以可向前向后遍历>

 

  •  ArrayList、Vector、LinkedList区别

 

ArrayList

Vector

LinkedList

结构

数组结构

数组结构

链表结构

线程是否同步

不同步

同步

不同步

线程是否安全

线程不安全

线程安全

线程不安全

 

java gui框架 java框架总结_数据_02

             ⑴ArrayList 与Vector的区别

相同点:ArrayList 与Vector都实现了Collection接口,它们都是有序集合,并且数据是可重复的

不同点:

               ①同步性:Vector线程同步、安全,ArrayList 线程不同步、不安全;由于Vector使用了synchronized方法(加锁,线程安全),通常性能比ArrayList 差。

               ②数据增长:Vector默认增长为原来的两倍,ArrayList默认增长为原来的1.5倍(依据jdk)。Vector 和ArrayList可以设置初始容量,即初始空间大小,Vector可以设置负载因子,即增长的空间大小,而ArrayList则没有提供可以设置负载因子的方法。

             ⑵ArrayList和LinkedList的区别

相同点:ArrayList和LinkedList都是线程不同步和线程不安全

不同点:ArrayList使用数组方式存储数据,此数组可存储的元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按下标查找元素,但是插入元素要涉及数组元素移动等内存操作,所以查询数据快而插入数据和删除数据慢;而LinkedList使用双向链表实现存储,按下标查找数据需要进行前向或后向遍历,但是插入数据和删除数据只需要记录本项的前后项即可,所以插入和删除速度快,而查询慢。

或者可以这样说,ArrayList查询快,写数据慢;LinkedList查询慢,写数据快。ArrayList查询快是因为底层是由数组实现,通过下标定位数据快。写数据慢是因为复制数组耗时。LinkedList底层是双向链表,查询数据依次遍历慢。写数据只需修改指针引用。

(但是如果详细去探索在不同场景下ArrayList和LinkedList的读写速度的话,那么LinkedList写入的速度不一定比ArrayList写入的速度,详细情况请看【】)   

应用场景:  平时项目中的查询所有操作使用的都是ArrayList;LinkedList ——贪食蛇游戏

package p2;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 *测试ArrayList和LinkedList的读写速度
 * 在集合中装5万条数据
 * @author Min.Z
 *
 */
public class Demo1 {
	static final int N=50000;
    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++){
        	list.get(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+"条耗时:"+readList(list2));
    }
}

3.Set接口

  • 特点:无序,对象不可重复
  • 遍历方式:

Set<Integer> set = new HashSet<Integer>();
        set.add(1);
        set.add(21);
        set.add(5);
        set.add(3);
        set.add(6);
        set.add(3);
        
        //1.foreach
        for (Integer n : set) {
            System.out.println(n);
        }
        
        //2.Iterator
        Iterator<Integer> it = set.iterator();
        while(it.hasNext()) {
            System.out.println(it.next());
        }
        
        //3.forEach
        set.forEach(cc -> System.out.println(cc));
        
        /**
         * 其结果都是1  3   21   5   6
         * Set无序并不代表没有规律。无论遍历多少遍或者用其它的方法遍历,打印的结果都是一样的。
         * 其原因是:因为里面的算法是一样的,都是哈希算法。对于这个我会有一篇博客专门讲解。
         */

  • HashSet、TreeSet、LinkedHashSet区别 

①.需要速度快的集合,使用HashSet

②.需要集合有排序功能,使用TreeSet

③.需要按照插入的顺序存储集合(插入数据的顺序和输出顺序是一样的),使用LinkedHashSet

4.Map接口

  • 特点:无序,以键值对的形式添加元素,键不能重复,值可以重复,键相同,值会覆盖
  • 遍历方式:

 Map<String, String> map = new HashMap<String,String>();        
        map.put("zs", "张三");
        map.put("ls", "李四");
        map.put("ww", "王五");
        map.put("zs", "王哈");
        map.put("hh", "哈哈");

//1.map.keySet()获得Map所有的键,返回一个Set集合并保存,再根据键去查找值
        Set<String> keySet = map.keySet();//map集合的key
        //①foreach
        for (String key : keySet) {
            System.out.println("键:"+key+"      值:"+map.get(key));
        }
        
        //②Iterator
        Iterator<String> it = keySet.iterator();
        String k = null;
        while(it.hasNext()) {
            k=it.next();
            System.out.println("键:"+k+"      值:"+map.get(k));
        }

//2.通过entrySet()方法将map集合中的映射关系取出(这个关系就是Map.Entry类型),再遍历此Set
        Set<Map.Entry<String, String>> entrySet = map.entrySet();//因为键不重复,所以取出的整体(Map.Entry)绝对不重复
        //①foreach
        for (Entry<String, String> entry : entrySet) {
            System.out.println("键:"+entry.getKey()+"      值:"+entry.getValue());

        }
        //②Iterator
        Iterator<String> it2 = keySet.iterator();
        String k2 = null;
        while(it2.hasNext()) {
            k2=it2.next();
            System.out.println("键:"+k2+"      值:"+map.get(k2));
        }

 

/**
         * 虽然使用keySet及entrySet来进行遍历能取得相同的结果,但两者的遍历速度是有差别的。
         * keySet():迭代后只能通过keySet()取key 
         * entrySet():迭代后可以entry.getKey(),entry.getValue()取key和value。返回的是Entry接口 (整体,映射关系)
         * 说明:keySet()的速度比entrySet()慢了很多,也就是keySet方式遍历Map的性能不如entrySet性能好
         * 所以当我们数据是海量的时候,使用entrySet遍历可优化程序性能
         */

 

/**
         * 思考:在Map中keySet()遍历中,我们获得的键都是Set集合,所以决定了Map集合的键是无序且不能重复的
         * 且Map的打印顺序都是根据键找值,就说明,即Map打印的顺序也与哈希算法有关。
         */

  • HashMap、TreeMap、LinkedHashMap区别 

 ①.在Map中插入、删除和定位元素,HashMap是最好的选择

②.需要集合有排序功能,使用TreeMap更好

③.需要按照插入的顺序存储集合,使用LinkedHashMap

 

  •  HashMap的实现原理

通过put和get存储和获取对象。

存储对象时,我们将K/V传给put方法时,它调用hashcode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量。

获取对象时,我们将K传递给get,他调用hashcode计算hash从而得到bucket位置,并进一步调用equals()方法确认键值对。