欢迎来到我的博客

将来的你一定会感激现在拼搏的自己

JavaSE基础day14集合

 


一. 集合概述

(一) 集合和数组的区别

1. 相同点: 两者都是数据存储容器,可以存储多个数据

2. 不同点:

  数组:

    1) 数组的长度是不可变的,集合的长度是可变的

    2) 数组可以存基本数据类型和引用数据类型

          int[] arr = new int[3];   String[] arr1 = new String[5];

       集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类

 

(二) 集合体系结构

List :

  1. 元素存取有序

  2. 元素有索引

  3. 存储的元素可以重复

 

Set:

  1. 元素存取无序

  2. 没有索引

  3. 不存储重复元素

 

二. 单列集合体系的详细讲解

(一) 顶层接口Collection常用功能

1. 概述: Collection是单列集合的顶层接口,定义的是所有单列集合中共有的功能. JDK不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现.

 

2. 创建Collection集合的对象:

  Collection接口,不能直接创建对象,因此找一个实现类ArrayList创建对象

  1) 多态: 多态的方式 -- 父类引用指向子类对象 Collection c = new ArrayList();

  2) 具体的实现类创建 -- 本类引用指向本类对象 ArrayList a = new ArrayList();

 

 

3. Collection集合常用方法:

  1) boolean add(Object e): 添加元素

  2) boolean remove (Object o): 从集合中移除指定的元素

  3) void clear(): 清空集合中的元素

  4) boolean contains(Object o): 判断集合中是否存在指定的元素

  5) boolean isEmpty(): 判断集合是否为空(集合存在,没有元素), 如果集合为空, 那么返回true, 如果集合不为空 false

  6) int size(): 返回集合中元素的数量,返回集合的长度。

  7) Object[] toArray(): 返回集合的对象的数组

复制代码
import java.util.ArrayList;
import java.util.Collection;

public class CollectionMethod {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        // 一个集合中只存储相同的数据类型
        // 1. boolean add(Object e): 添加元素
        c.add("abc");
        c.add("hello");
        c.add("he");
        c.add("hi");
        System.out.println(c);// [abc, hello, he, hi]

        // 2. boolean remove (Object o): 从集合中移除指定的元素
        c.remove("hello");
        System.out.println(c);// [abc, he, hi]
        c.remove("world");
        System.out.println(c);// [abc, he, hi]

        // 3. boolean contains(Object o): 判断集合中是否存在指定的元素
        System.out.println(c.contains("abc"));// true
        System.out.println(c.contains("world"));// false

        // 4.boolean isEmpty(): 判断集合是否为空(集合存在,没有元素),
        // 如果集合为空, 那么返回true, 如果集合不为空 false
        System.out.println(c.isEmpty());// fasle
        System.out.println(c.size());// 3

        // 5. void clear(): 清空集合中的元素
        c.clear();

        System.out.println(c);// []
        System.out.println(c.isEmpty());// true

        // 6. int size(): 返回集合中元素的数量,返回集合的长度
        System.out.println(c.size());// 0
    }
}
复制代码

 

toArray遍历

复制代码
import java.util.ArrayList;
import java.util.Collection;
public class ConnectionToArray遍历 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add(15);
        c.add(1);
        c.add(-8);
        System.out.println(c);

        // 1. 将集合容器c转换成一个数组容器
        Object[] objArr = c.toArray();
        // 2. 遍历数组相当于间接遍历容器
        for(int index = 0; index < objArr.length; index++){
            Object obj = objArr[index];
            Integer i = (Integer)obj;
            System.out.println(i);
        }
    }
}
复制代码

 

(二) 单列集合的遍历

2.1迭代器遍历

通过迭代器添加add()会在当前位置后加入值

1. 迭代: 更新换代, 从一个到下一个概念, 迭代相当于遍历的含义

2. 迭代器: 专门对于单列集合进行遍历的对象, 称为迭代器

3. 获取集合迭代器的方法

        Iterator<E> iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到

       方法的返回值结果是Iterator接口, 证明这个方法实际返回的应该是这个接口的实现类对象

4. Iterator中的常用方法:

        - boolean hasNext(): 判断当前位置是否有元素可以被取出

        - E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置

        - void remove(): 删除迭代器对象当前指向的元素

 

hashNext和next功能的运行方式:

 

复制代码
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Connection迭代器遍历 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add(3.14);
        c.add(2.1);
        c.add(-0.3);
        c.add(99.0);

        // 1. 获取到c集合的迭代器对象
        Iterator it = c.iterator();
        // 2. 循环获取出集合c中的每一个元素
        // hasNext() : 判断集合中是否还有下一个元素
        while(it.hasNext()){
            // 获取出集合中的元素
            Object obj = it.next();
            Double d = (Double)obj;
            System.out.println(d);
        }

        // System.out.println(it.next());

        /*System.out.println(it.next());
        System.out.println(it.next());
        System.out.println(it.next());
        System.out.println(it.next());
        // NoSuchElementException : 将集合中所有元素都遍历完毕,还想继续向下获取元素,报出次异常
        // 没有这个元素异常
        System.out.println(it.next());*/
    }
}
复制代码

 

2.2增强for(foreach)遍历

1.概述:

  1) 增强for是JDK5之后出现的,其内部原理是一个Iterator迭代器

  2) 实现Iterable接口的类才可以使用迭代器和增强for简化数组和Collection集合遍历

 2.格式:

        for(集合/数组中元素的数据类型 变量名 : 集合/数组名){

       // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可

        }

复制代码
import java.util.ArrayList;
import java.util.Collection;

public class Collection增强for遍历 {
    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add(15);
        c.add(1);
        c.add(-8);

        /*
           for(数据类型  变量名 : 遍历的集合或者数组){
           }
           数据类型就是集合或者数组中存储的数据类型; 变量名表示每一次循环中, 依次表达集合或数组中的每一个元素
         */

        for(Object obj : c){
            System.out.println((Integer)obj);
        }

        int[] arr = {12,13,14,15};
        for(int i : arr){
            System.out.println(i);
        }
    }
}
复制代码

 

(三) 有序单列集合List

3.1概述

1. 概述: List集合是Collection接口的子接口,其下有两个常用实现类分别为 ArrayList 和 LinkedList

2. List集合特点:

  1) 有序:元素存入集合与从集合中取出的顺序一致

  2) 有索引:每个元素都有自己的索引编号,从0开始,到集合长度-1为止

  3) 元素可以重复:即使是值相同的几个元素,位置和索引也各不相同,可以区分这几个值

3. List集合的特有方法:

  1) void add(int index,E element): 在此集合中的指定位置插入指定的元素

  2) E remove(int index): 删除指定索引处的元素,返回被删除的元素

  3) E set(int index,E element): 修改指定索引处的元素,返回被修改的元素

  4) E get(int index):返回指定索引处的元素

 

 

4. 针对List集合特有的遍历方式

  可以通过集合的size方法获取list集合索引的范围,根据索引通过get方法可以获取指定索引的值。

 

特有方法代码

复制代码
import java.util.ArrayList;
import java.util.List;
public class ListSpecialMethod {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(12);
        list.add(99);
        list.add(1);
        System.out.println(list);// [12, 99, 1]

       // 1)void add(int index,E element): 在此集合中的指定位置插入指定的元素
        list.add(2,22);// [12, 99, 22, 1]
        System.out.println(list);

        // 2)E remove(int index): 删除指定索引处的元素,返回被删除的元素
        Object obj = list.remove(1);
        System.out.println(obj);// 99
        System.out.println(list);// [12, 22, 1]

        //3)E set(int index,E element): 修改指定索引处的元素,返回被修改的元素
        Object obj1 = list.set(0,888);
        System.out.println(obj1);// 12
        System.out.println(list);// [888, 22, 1]

        //4)E get(int index):返回指定索引处的元素
        Object obj2 = list.get(2);
        System.out.println(obj2);// 1
    }
}
复制代码

 

List集合特有遍历方式

复制代码
import java.util.ArrayList;
import java.util.List;

public class List遍历 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(12);
        list.add(99);
        list.add(1);

        for(int index = 0; index < list.size(); index++){
            Object obj = list.get(index);
            System.out.println(obj);
        }
    }
}
复制代码

 

3.2 并发修异常的产生原因和解决办法

1. ConcurrentModificationException 并发修改异常

 

2.异常发生原因: 在迭代器遍历过程中使用集合的引用进行元素的添加或删除

3. 解决方法:

        (1) 通过for循环(索引遍历法)遍历集合,在遍历过程中可以进行添加和删除元素

    (2) 使用迭代器中的remove()方法删除集合元素

(3) 使用List集合的特有迭代器ListIterator<E>, 通过List中的方法listIterator()获取, 该迭代器允许迭代期间修改列表      

-- add(E e) 添加元素

        -- remove() 移除元素

 

案例 : 定义一个List集合, 存储字符串数据”ok”,”java”,”hello”,”world”, 迭代器遍历集合元素, 如果集合中存在”hello”字符串,向集合中添加”end”字符串

复制代码
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class 并发修改异常 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("ok");
        list.add("java");
        list.add("hello");
        list.add("world");
        // changeList(list);
        // changeListIterator(list);
        changeListFor(list);
    }

    // 案例 : 定义一个List集合, 存储字符串数据”ok”,”java”,”hello”,”world”,
    // 迭代器遍历集合元素, 如果集合中存在”hello”字符串,向集合中添加”end”字符串
    // changeList方法会发生并发修改问题
    public static void changeList(List list){
        // 1. 使用迭代器遍历list集合
        Iterator it = list.iterator();
        while(it.hasNext()){
            String str = (String)it.next();
            if("hello".equals(str)){
                // ConcurrentModificationException
                // 并发          修改        异常
                // 发生原因: 如果对于集合一边使用迭代器遍历,一边修改集合中的数据内容,那么可能并发修改异常
                list.add("end");
            }
        }
        System.out.println(list);
    }

    // changeListIterator可以解决并发修改问题
    public static void changeListIterator(List list){
        ListIterator it = list.listIterator();
        while(it.hasNext()){
            String str = (String)it.next();
            if("hello".equals(str)){
                // 解决并发修改异常的关键: 就是迭代的过程中,不允许通过集合对象修改集合元素(新增,删除)
                // 必须使用迭代器进行集合中元素的修改, 才能解决并发修改异常问题
                it.add("end");
            }
        }
        System.out.println(list);
    }

    // List集合特有索引遍历方式, 可以解决并发修改问题
    public static void changeListFor(List list){
          for(int index = 0; index < list.size(); index++){
              String str = (String)list.get(index);
              if("hello".equals(str)){
                  // list.add(0,"end"); 死循环
                  list.add("end");
              }
          }
        System.out.println(list);
    }

// 增强for循环也会有并发修改问题: 因为底层也是迭代器实现的
public static void changeListForEach(List list){
    for(Object obj : list){
        String str = (String)obj;
        if("hello".equals(str)){
            // list.add(0,"end"); 死循环
            list.add("end");
        }
    }
    System.out.println(list);
}
}
复制代码

 

(四) 数据结构之栈和队列

数据结构是计算机存储,组织数据的方式,通常情况下, 精心选择的数据结构可以带来更高的运行和存储效率

4.1栈

栈: stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。

 

特点: 先进后出,(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。

 压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。

 弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

 

4.2队列

   queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。

   特点:

1) 先进先出(即,存进去的元素,要在它前面的元素依次取出后,才能取出该元素)。例如,小火车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。

2) 队列的入口、出口各占一侧。例如,下图中的左侧为入口,右侧为出口

 

 

4.3数据结构之数组和链表

1.数组:

  Array:是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。

特点查找元素快:

        通过可以快速访问指定位置的元素

增删元素慢:

        指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。如下图

指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。如下图

 

 

2.链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表。

 

3.简单的说,采用该结构的集合,对元素的存取有如下的特点:

多个结点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的右手拉住下个人的左手,依次类推,这样多个人就连在一起了。

 

 

查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素

增删元素快: 增加元素 --> 只需要修改连接下个元素的地址即可。

删除元素:只需要修改连接下个元素的地址即可。

 

 

4.4 ArrayList和LinkedList对比分析

1. ArrayList集合:

  (1) 在创建ArrayList集合对象的时候,会维护一个长度为10的Object类型的数组.

  (2) 当插入数据10个长度不够,这时候以1.5倍的形式进行扩容

  (3) 存储特点 : 查询快, 增删慢

 

 

3.LinkedList:集合数据存储的结构是链表结构。方便元素添加、删除的集合。

LinkedList是一个双向链表,特点 : 查询慢, 增删快, 链表结构不需要连续内存空间, 可以利用内存中零散空间

 

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方法我们作为了解即可:

 

public void addFirst(E e):将指定元素插入此列表的开头.

public void addLast(E e):将指定元素添加到此列表的结尾。

public E getFirst():返回此列表的第一个元素。

public E getLast():返回此列表的最后一个元素。

public E removeFirst():移除并返回此列表的第一个元素。

public E removeLast():移除并返回此列表的最后一个元素。

复制代码
import java.util.LinkedList;
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.addFirst("1");
        list.addFirst("2");
        System.out.println(list);// [2, 1]

        list.addLast("end");
        list.addLast("ok");
        System.out.println(list);// [2, 1, end, ok]

        list.removeFirst();
        System.out.println(list);// [1, end, ok]
        list.removeLast();
        System.out.println(list);// [1, end]

        String str = (String)list.getFirst();
        System.out.println(str);// 1
        Object obj = list.getLast();// Object obj = "end";  String s = (String)obj;
        System.out.println(list.getLast());// end
    }
}
复制代码

 

案例:

测试: ArrayList和linkedList首尾增加元素, 首尾删除元素, 首尾获取元素的性能

复制代码
import java.util.ArrayList;
import java.util.LinkedList;

public class ArrayListAndLinkedList比较 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        ArrayListAdd(list);
        LinkedList list1 = new LinkedList();
        LinkedListAdd(list1);

        ArrayListGet(list);
        LinkedListGet(list1);

        ArrayListDelete(list);
        LinkedListDelete(list1);
    }
    // 测试: ArrayList和LinkedList首尾增加元素, 首尾删除元素, 首尾获取元素的性能
    // 1. 测试ArrayList首尾新增功能
    public static void ArrayListAdd(ArrayList list){// 0x12
         long beginTime = System.currentTimeMillis();
         for(int i = 1; i <= 10000; i++){
             list.add(0,"first");
             list.add(list.size()-1,"end");
         }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    }

    // 2. 测试LinkedList首尾新增功能
    public static void LinkedListAdd(LinkedList list){
        long beginTime = System.currentTimeMillis();
        for(int i = 1; i <= 10000; i++){
            list.addFirst("first");
            list.addLast("end");
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    }

    // 3. 测试ArrayList首尾获取功能
    public static void ArrayListGet(ArrayList list){
        long beginTime = System.currentTimeMillis();
        for(int i = 1; i <= 10000; i++){
            list.get(0);
            list.get(list.size()-1);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    }

    // 4. 测试ArrayList首尾获取功能
    public static void LinkedListGet(LinkedList list){
        long beginTime = System.currentTimeMillis();
        for(int i = 1; i <= 10000; i++){
            list.getFirst();
            list.getLast();
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    // 5. 测试ArrayList首尾删除功能
    public static void ArrayListDelete(ArrayList list){
        long beginTime = System.currentTimeMillis();
        for(int i = 1; i <= 10000; i++){
            list.remove(0);
            list.remove(list.size()-1);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    }

    // 6. 测试ArrayList首尾删除功能
    public static void LinkedListDelete(LinkedList list){
        long beginTime = System.currentTimeMillis();
        for(int i = 1; i <= 10000; i++){
            list.removeFirst();
            list.removeLast();
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - beginTime);
    }
}
复制代码

 

posted @   晴天般的微  阅读(151)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示

目录导航