Java集合

Posted Guarding and trust

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java集合相关的知识,希望对你有一定的参考价值。

不为失败找理由,只为成功找方法。所有的不甘,因为还心存梦想,所以在你放弃之前,好好拼一把,只怕心老,不怕路长。

文章目录


一、引入集合框架

    回忆一下Java能够储存数据的类型。字符串:可以存储一堆字符,但是它的限制太多了,数据不便于储存;数组:可以存储相同类型的数据,这倒是比字符串多了一些权限,只有是类型相同的数据,无论是对象还是基本数据类型,都可以存储。那么又有一个问题了,如果一个场景,当前不知道要存储多少数据,多少个对象,这使用数组就很麻烦了,我们都知道数组一旦定义下来,那么它的长度就固定了,虽然可以拷贝数组,这代码量和性能就不可控了。那么这时候一个框架出现了,那么就是集合(或叫容器)。集合和数组最大的特点就是它的长度是可变的,由此就可以解决刚才的场景了,那么接下来就来学习一下集合是个什么东西。

二、集合家族体系

    集合是在java.util库下的,它有两大阵营,Collection和Map。Collection是单列的,Map是双列的,简单的说就是Collection里的实现是由一个独立元素组成的序列;Map是由键值对组成,使用键来找值。下图是集合结果图:

以上就是集合类的结构图,有些实现类没有列举出来,但是以上的都是比较常用的,经典的实现类。
如果把上面的实现类掌握了,那么这个集合框架就掌握的差不多了。

三、集合顶级接口 — Collection

1、简介

    由上图可知,结合的顶级接口是Collection,到这里你可以会有疑惑,前面明显还有一个Iterator,这个是集合遍历使用的,叫迭代器。因此集合的顶级父类是Collection,而实现了这个接口的类,就是单列的集合。我们又可以知道Collection下面有三个子接口,分别是:List、Set、Queue,这三个接口才是区分单列集合的各有所长之处。List必须按照元素插入顺序来保存;Set中不能存在重复元素;而Queue则要按照排队规则来输出元素(通常与元素被插入的顺序一样)。
    Map是集合另一个阵营的(这里有很多人会混为Map继承了Collection),它在某种意义上将数值与对象关联在一起了。 就是使用另一个对象查找某一个对象,所以它也被称为关联数组,或者称字典。 因为它使用一个键对象来查询一个值对象,就像我们在字典中使用一个单词来查其定义一样。Map是非常强大的编程工具。

2、Collection接口常用方法

    这个接口的方法有很多,不过我们不需要把全部方法都记忆,我们把几个常用的,重点关注就行了。看API之前,我们先思考一下一个容器,最基本的操作是什么呢?把一个对象放进去、取出来、该对象是否存在容器?这些是我们猜想的,下面我们来看看常用的API:

方法描述
int size()获取当前集合的大小
boolean add(E e)给该集合添加指定对象
boolean remove(Object o)在该集合中查找对象o,存在则删除
void clear()清空该集合元素
boolean isEmpty()判断当前集合是否为空
boolean contains(Object o)判断o对象是否在该集合中
Iterator iterator()迭代器,该迭代器对象默认指向当前集合的0索引。集合遍历专属
boolean addAll(Collection<? extends E> c)集合合并
Object[] toArray()把集合中的元素存储到数组中

我们刚刚猜想的方法还是有的,添加操作(add)、删除操作(remove)、判断该对象是否存在(contanins)。接下来就开始正题了,除了以上的通用方法外,List、Set、Queue它们各有什么独特方法呢,我们拭目以待。

四、List系列

1、特点

    List系列的集合的特点是:有序列、可重复、有索引,其下面典型的实现类分别是ArrayList和LinkedList,这里我们也只讲解这两个类。
    首先是它们的底层实现以及特点:

	ArrayList:基于数组实现的,默认长度为10;特点是根据索引查询速度快,增删操作相对慢。
	LinkedList:基于双链表实现;特点是查询效率低,增删首尾元素效率高,线程不安全。

2、ArrayList详解

    现在我们已经知道了ArrayList是基于数组实现的,数组我们已经很熟悉了,那么它的底层真的有数组的身影?我们不妨进入源码查看一番。

public class ArrayList<E> implements List<E>
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;

    transient Object[] elementData; 
    

 public ArrayList() 
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    
    

以上是ArrayList的源码,我们来看看无参构造,当我们用关键字new的时候,它就创建了一个空的数组,不过这种创建方式和我们平时创建的有些不一样,不过我们的目的是看是否使用了数组,后面的我们暂时不用深入了解。

    接下来是特点,刚刚我们讨论到ArrayList查询速度快,快的元素是它可以根据索引来查询,那么我们应该想到这个类应该有很多关于索引的方法了。关于索引比较常用的方法如下表:

方法描述
void add(int index, E element)在此集合中的指定位置插入指定的元素
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index)修改指定索引处的元素,返回被修改的元素
E get(int index)返回指定索引处的元素

3、LinkedList详解

    我们需要先知道什么是双链表。我们先看图:

双链表上的每个结点都有 4个值,l-Nnext 指针表示它左边的结点的下标,r-Nnext 指针表示它右边的结点的下标,其他的数组和变量和单链表的存储代表一个意思。这也就是说,首尾操作对于LinkedList来说的很简单的,那么它的独特方法就出来了,我们来看看操作首尾的方法:

方法描述
public void addFirst(E e)在该列表开头插入指定的元素
public void addLast(E e)将指定的元素追加到此列表的末尾
public E getFirst()返回此列表中的第一个元素
public E getLast()返回此列表中的最后一个元素
public E removeFirst()从此列表中删除并返回第一个元素
public E removeLast()从此列表中删除并返回最后一个元素

案例:模拟栈与队列
首先我们得清楚栈与队列的出入顺序,栈:先进后出,后进先出原则;队列:先进先出,后进后出原则。知道了这个规则,我们就来使用LinkedList模拟一下吧:

 public static void main(String[] args) 
        LinkedList<String> list = new LinkedList<>();
        //模拟栈 先进后出
        System.out.println("进栈/压栈");
        list.addFirst("java");
        list.addFirst("mysql");
        list.addFirst("spring");
        list.addFirst("python");
        list.addFirst("vue");
        System.out.println("全部进入完毕,出栈/弹栈:");
        System.out.println(list.getFirst());
        list.removeFirst();
        System.out.println(list);

        System.out.println(list.getFirst());
        list.removeFirst();
        System.out.println(list);

		System.out.println(list.getFirst());
        list.removeFirst();
        System.out.println(list);

        list.removeFirst();
        System.out.println(list);
        System.out.println(list.getFirst());

        list.removeFirst();
        System.out.println(list);

		//队列:先进先出
        System.out.println("开始归队");
        list.addLast("java");
        list.addLast("mysql");
        list.addLast("spring");
        list.addLast("python");
        list.addLast("vue");
        System.out.println("全部归队完毕,开始出列:");
        System.out.println(list.getFirst());
        list.removeFirst();
        System.out.println(list);

        System.out.println(list.getFirst());
        list.removeFirst();
        System.out.println(list);

        System.out.println(list.getFirst());
        list.removeFirst();
        System.out.println(list);

        list.removeFirst();
        System.out.println(list);
        System.out.println(list.getFirst());

        list.removeFirst();
        System.out.println(list);
    

执行结果图:

细心的你也许发现了一个问,上面的例子为啥不使用循环呢,因为使用for循环如果不小心的话会出现问题,您实一下就清楚了。如果想使用循环的话,可以参照以下代码:

LinkedList<String> list = new LinkedList<>();
        //模拟栈 先进后出
        System.out.println("进栈/压栈");
        list.push("java");
        list.push("mysql");
        list.push("spring");
        list.push("python");
        list.push("vue");
        System.out.println("全部进入完毕,出栈/弹栈:" +list.size());
        for (int i = 0; i <list.size()+5 ; i++)   //条件也可以写成:i < 5
            System.out.println(list.getFirst());
            System.out.println(list);
            list.removeFirst();
        

执行结果是一样的。


五、小结

本章简单的介绍了Java集合框架的家族体系,简单的说就是被Collection和Map两个接口继承的实现类,即为集合类库。

以上是关于Java集合的主要内容,如果未能解决你的问题,请参考以下文章

类LinkedList(集合)

类LinkedList

Java集合的详细研究9Java堆栈(stack)的使用方法

JAVA面试总结--集合

Java中的集合框架(JCF)

零基础学Java—LinkedList集合(四十)