集合概述

概述

我们都知道,数组的长度是不可变的, 当元素的个数超过数组的长度之后, 我们就只能通过创建长度更长的新数组的方式来存储元素, 太麻烦了

集合给我提供另外一种容器的概念,可变长度的容器, 这样,程序在使用的时候就不需要再考虑容器容量的问题,从而可以更加专心于业务

我们要知道,java中数组是唯一的底层容器,所有, 集合是开发者使用java规范制作的逻辑上的容器

数组和集合的区别

区别1

数组既可以存储基本数据类型, 又可以储存引用数据类型,基本数据类型存储的是值, 引用数据类型储存的是地址值

集合只能存储引用数据类型(对象的引用), 其实集合也可以存储基本数据类型, 但是在存储的时候自动装箱变成包装类对象

区别2

数组长度是固定的,不能自动增长

集合的长度的是可变的,可以根据元素的增加而增长

使用场景

如果元素的个数是固定的,推荐使用数组

如果元素的个数不固定,推荐使用集合(日常开发中,使用集合比较普遍)

集合体系图

集合分类

Collection集合

单列集合, 直接存储对象的引用

Map集合

双列集合, 使用key-value的形式, 每个元素会有一个唯一的名称

三. Collection集合

定义

Collection是单列集合, 用于存储单个元素

Collection是一个接口, 他的下面有多个子接口和实现类, 我们称之为Collection体系

分类

List  集合中的元素是有序的,可以存放重复元素

Queue 队列, 除优先级外, 保持先进先出的原则(基本不用)

Set 集合中的元素是无序的, 不能存放重复的元素

体系图

常用方法

boolean add(E e)    添加元素

boolean remove(Object o)    从此 collection 中移除指定元素的单个实例,如果存在的话

void clear()    移除此 collection 中的所有元素

boolean contains(Object o)    判断集合中是否包含指定元素

boolean isEmpty()    判断集合中元素的个数是否为空

int size()    获取集合中元素的个数

案例演示

publicstaticvoidmain(String[]args) {

  //如果没有泛型,会报出警告,不影响运行

    Collectioncollection=newArrayList<>();


    Studentstudent1=newStudent("小红",18);

    Studentstudent2=newStudent("小明",19);


    collection.add(student1);  //添加方法

    collection.add(student2);


    //判断集合中是否包含某个元素

    System.out.println(collection.contains(student1));//结果为 : true


    //判断集合中元素的个数是否为null

    System.out.println(collection.isEmpty());//结果: false


    //获取集合中元素的个数

    System.out.println(collection.size());//结果为 : 2


    //移除某个元素

    System.out.println(collection.remove(student2));//结果:true

    System.out.println(collection.size());//结果: 1


    //清空集合中的元素

    collection.clear();

    System.out.println(collection.size());//结果为0

}

集合中所有带All的方法

boolean addAll(Collection c) 将指定 collection 中的所有元素都添加到此 collection 中

boolean removeAll(Collection c)    移除此 collection 中那些也包含在指定 collection 中的所有元素

boolean containsAll(Collection c)    如果此 collection 包含指定 collection 中的所有元素

boolean retainAll(Collection c)    仅保留此 collection 中那些也包含在指定 collection 的元素

演示

publicstaticvoidmain(String[]args) {

    Collectioncollection=newArrayList<>();


    Studentstudent1=newStudent("小红",18);

    Studentstudent2=newStudent("小明",19);


    collection.add(student1);  //添加方法

    collection.add(student2);


    Collectioncollection2=newArrayList<>();


    Studentstudent3=newStudent("小辉",18);

    collection2.add(student1);

    collection2.add(student3);


    //将collection2集合中的元素添加到collection集合中

    collection.addAll(collection2);

    System.out.println(collection.size());//结果: 4

    //判断collection集合中是否包含collection2集合中的所有元素

    booleanflg=collection.containsAll(collection2);

    System.out.println(flg);//结果: true


    //仅在collection中保留两个集合中相同的元素

    collection.retainAll(collection2);

    System.out.println(collection.size());//结果: 3

}

四. 迭代器

定义

集合是用来存储元素,存储的元素需要查看,那么就需要迭代(遍历)

案例演示遍历集合

publicstaticvoidmain(String[]args) {

    Collectioncollection=newArrayList<>();


    Studentstudent1=newStudent("小红",18);

    Studentstudent2=newStudent("小明",19);

    Studentstudent3=newStudent("小辉",18);


    collection.add(student1);  //添加方法

    collection.add(student2);

    collection.add(student3);


    //集合转数组进行遍历

    Object[]obs=collection.toArray();


    for(inti=0;i

        System.out.println(obs[i]);//前提集合内的元素重写了toString()方法

    }

}

迭代器的遍历形式

步骤

获取迭代器

调用hashNext()方法判断下一个元素是否存在

调用next()方法获取元素

演示

publicstaticvoidmain(String[]args) {

    Collectioncollection=newArrayList<>();


    Studentstudent1=newStudent("小红",18);

    Studentstudent2=newStudent("小明",19);

    Studentstudent3=newStudent("小辉",18);


    collection.add(student1);  //添加方法

    collection.add(student2);

    collection.add(student3);


    //for循环的形式

    for(Iteratorit=collection.iterator();it.hasNext();){

        Studentstudent=it.next();

        System.out.println(student);

    }


    //while循环的形式

    Iteratorit=collection.iterator();

    while(it.hasNext()){

        Studentstudent=it.next();

        System.out.println(student);

    }

}

迭代器工作原理

Iterator是一个接口,规定了迭代器的基本使用, 集合的子类都实现了迭代器方法, 同时返回属于自己的迭代器对象

迭代器相当于是集合的一个副本, 里面记录了集合的基本属性值.

使用时,我们先调用hashNext方法判断是否有下一个元素,如果有则返回true,否则返回false

然后调用next()方法,返回当前指针所在位置上的元素

修改集合导致的异常

当我们使用迭代器遍历集合的时候,如果对集合进行了修改,下一次循环会报错

原因: 集合会记录修改的次数, 如果迭代器发现集合副本和原集合修改次数不一样的话就会报错

解决办法: 使用迭代器的删除方法

演示

publicstaticvoidmain(String[]args) {

    Collectioncollection=newArrayList<>();


    Studentstudent1=newStudent("小红",18);

    Studentstudent2=newStudent("小明",19);


    collection.add(student1);  //添加方法

    collection.add(student2);

    //while循环的形式

    Iteratorit=collection.iterator();

    while(it.hasNext()){

        Studentstudent=it.next();

        //collection.remove(student);

it.remove();

    }

}

五. List集合

定义

List集合是有序的,可以储存重复的数据

List集合通过记录元素在集合中的位置来准确的查找元素

List集合体系

ArrayList    底层使用数组(线程不安全)

LinkedList    底层使用链表

Vector    底层使用数组(线程安全的,不推荐使用)

六. ArrayList集合

定义

低层使用的是数组, 所以其特性非常接近于数组

储存的元素是有序的,而且可以重复存储, 通过数组角标来查询更改元素,速度非常快

由于每次增删都要改动数组中的角标,所有导致增删效率低下

ArrayList的增删改查原理

ArrayList 集合初始化会有一个默认长度是10的数组, 内部还有一个记录当前元素个数的变量, 当储存的元素个数超过数组长度之后,容量就会扩充一半 

当我们去查询集合中的元素时, 需要提供给集合一个角标值, 然后通过这个角标值查找集合中的元素

当我们去删除一个元素的时候, 集合就会根据角标删除这个元素,并且改动其他元素的位置,这就是导致增删缓慢的原因

其实如果我们是连续往集合尾部插入数据的话, 速度其实是非常快的, 因为其他元素的位置不需要改动,但是如果我们插入数据的位置是数组的前面或者中间,速度就会有明显的降低

构造方法

ArrayList()    构造一个初始化容量为10的空列表

ArrayList(Collection  e)    构造一个包含执行集合元素的列表

ArrayList(int initialCapacity)    构造一个具有指定初始容量的空列表

常用方法

boolean add(E e)    将指定的元素添加到此列表的尾部

void add(int index,E element)    将指定的元素插入此列表中的指定位置

boolean contains(Object o)    如果此列表中包含指定的元素,则返回true

E get(int index)    通过角标查找元素

int indexOf(Object o)    返回此列表中首次出现的指定元素的索引, 或如果没有则返回 -1

int lastIndexOf(Object o)  返回此列表中最后一次出现的指定元素的索引(从后先前查)没有返回-1

boolean remove(Object o)    移除此列表中首次出现的指定元素(如果存在)

E set(int index , E element)    用指定元素替代此列表中指定位置上的元素,返回原来的元素

int size()    返回此列表中的元素数

演示

publicstaticvoidmain(String[]args) {

    ArrayListlist=newArrayList<>();


    //添加元素

    list.add("小红");

    list.add("小明");

    //将元素添加到角标1上

    list.add(1,"小辉");


    System.out.println(list.contains("小明"));//true


    //通过角标获取

    Stringstr=list.get(1);

    System.out.println(str);//结果: 小辉


    //通过元素获取角标

    System.out.println(list.indexOf("小明"));//结果 : 2


    //通过角标移除元素

    System.out.println(list.remove(1));//结果: true


    //通过角标设置元素

    System.out.println(list.set(1,"小李"));//小辉


}

ArrayList集合的遍历

for 循环遍历, 基本上等同于数组

演示

publicstaticvoidmain(String[]args) {

    ArrayListlist=newArrayList<>();


    list.add("小红");

    list.add("小明");

    list.add("小辉");


    for(inti=0;i

        System.out.println(list.get(i));

    }

}

迭代器 使用公用迭代器

演示

publicstaticvoidmain(String[]args) {

    ArrayListlist=newArrayList<>();


    list.add("小红");

    list.add("小明");

    list.add("小辉");


    Iteratorit=list.iterator();

    while(it.hasNext()) {

        Stringstr=it.next();

        System.out.println(str);

    }

}

迭代器2 List集合的迭代器(ListIterator) 可以从后往前遍历

演示

publicstaticvoidmain(String[]args) {

    ArrayListlist=newArrayList<>();


    list.add("小红");

    list.add("小明");

    list.add("小辉");


    ListIteratorit=list.listIterator();

    while(it.hasNext()) {

        Stringstr=it.next();

        System.out.println(str);

    }


    while(it.hasPrevious()){

        Stringstr=it.previous();

        System.out.println(str);

    }

}

测试题

去除集合中的重复字符串元素

演示

publicstaticvoidmain(String[]args) {

    ArrayListlist=newArrayList();

    list.add("a");

    list.add("b");

    list.add("b");

    list.add("b");

    list.add("c");

    list.add("c");

    list.add("c");

    list.add("c");

list.add("a");


    System.out.println(list);

    ArrayListnewList=getSingle(list);

    System.out.println(newList);

}

七. LinkedList集合

定义

底层使用的是链表,就好像一条锁链

这个集合中的每个元素都被封装到一个叫Node的内部类中, 然后记录上一个元素和下一个元素的地址,通过手拉手形成一个链条

增删快, 查询慢

增删改查的原理

当需要去查询LinkedList集合中的元素时,需要从最开始的元素查找起,然后一层一层往后找,直到找到该元素,这样的动作十分消耗性能

当需要去删除元素的时候, 我们只需要将被删除元素两端的元素重新连接到一起,或者新增的时候将新元素和左右两边的元素连起来就可以了

构造方法

LinkedList()    构造一个空列表

LinkedList(Collection e)    构造一个包含指定collection中元素的列表

常用方法

E remove()    获取并移除此列表的头

E poll() 获取并移除此列表的头

E peek() 获取但不移除此列表的头

演示

publicstaticvoidmain(String[]args) {

    LinkedListlist=newLinkedList<>();


    list.add("小红");

    list.add("小明");

    list.add("小辉");


    System.out.println(list.remove());//结果: 小红

    System.out.println(list.size());//结果:2


    System.out.println(list.poll());//结果: 小明

    System.out.println(list.size());//结果:1


    System.out.println(list.peek());//结果: 小辉

    System.out.println(list.size());//结果:1

}

八. ArrayList, LinkedList 及Vector集合之间的区别

线程安全

Vector : 线程安全

ArrayList, LinkedList : 线程不安全

实现方式

LinkedList : 链表

ArrayList,Vector : 数组

扩容

ArrayList和Vector使用数组实现, 当数组长度不够,内部会创建一个更大的数组

LinkedList 不存在这方面的问题

速度

ArrayList 查改块, 增删慢

LinkedList 查改慢, 增删快

你可能感兴趣的:(集合概述)