Java集合详细讲解

本文详细讲解了集合及其常用的API,还有其底层实现原理。保证让你看完彻底明白Java中的集合以及使用。

在java中集合有两大类:Collection和Map,先来看collection。

Collection

collection是单列集合的祖宗接口,他的功能是全部单列集合都可以继承使用的

Collection中常用的方法

java 复制代码
public boolean add(E e);//把给定对象添加到当前集合中
public void clear();//清空集合中所有元素
public boolean remove(E e);//删除
public boolean contains(Object obj);//判断当前集合是否包含obj
public boolean isEmpty();//判断集合是否为空
public int size();//返回集合元素的个数(长度)

Collection是一个接口,不能直接创建它的对象,只能利用多态创建。如下:

java 复制代码
public class CollectionDemo1 {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        System.out.println(coll);
       //删除不能通过索引删除 只能通过元素对象删除
        coll.remove("aaa");
        System.out.println(coll);

        //判断元素是否包含
        //contains底层依赖equals判断
        //注意:如果是自定义对象 必须要重写equals方法,因为equals比较的是地址值,不是变量值
        boolean re = coll.contains("bbb");
        System.out.println(re);
        
        //判断集合是否为空
        boolean r1 = coll.isEmpty();
        System.out.println(r1);
        
        //获取集合长度
        int l = coll.size();
        System.out.println(l);
    }
}

Collection的遍历

在java中很少使用普通for循环进行遍历,因为Set集合是没有索引的。下面介绍几种常用的遍历。

其中如果在遍历的过程中需要删除元素,请使用迭代器;如果仅仅是遍历,使用增强for或者Lambda表达式。

迭代器遍历

java 复制代码
Iterator<String> it = list.iterator();//获取迭代器
while(it.hasNext()){//判断当前位置是否有元素
	String str = it.next();//获取当前位置元素,并将迭代器移动到下一位置
	System.out.println(str);
}

增强for遍历

  • 增强for的底层就是迭代器,为了简化迭代器的代码书写的。
  • 它是JDK5之后出现的,其内部原理就是一个Iterator迭代器。
  • 所有的单列集合和数组才能用增强for进行遍历。
    使用格式如下:
java 复制代码
for(String s:List){
	System.out.println(s);
}
java 复制代码
public class demo {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        //s就是第三方变量,在循环中依次表示集合中的一个数据
        //快捷方式 集合名字+ for +回车
        for(String s: coll){
            System.out.println(s);
        }
    }
}

细节注意⚠️

  • 修改增强for中的变量,不会改变集合中原本的数据。

Lambda表达式遍历

它是在JDK8开始的新技术,提供一种更简单、更直接的遍历集合的方式。

java 复制代码
public class demo {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        //利用匿名内部类表示
        coll.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        //利用Lambda表达式表示
        coll.forEach(s -> System.out.println(s));
    }
}

List集合

List集合的特点:

  • 有序:存和取的元素顺序一致。
  • 有索引:可以通过索引操作元素。
  • 可重复:存储的元素可以重复。
  • List继承了Collection的方法
  • 因为List有索引,所以增强了所以操作方法

List集合特有索引的方法

java 复制代码
public class demo {
    public static void main(String[] args) {
       List<String> list = new ArrayList<>();
       list.add("aaa");
       list.add("bbb");
       list.add("ccc");
       System.out.println(list);
       
       
       // 在指定位置添加数据
        list.add(1,"ddd");
       System.out.println( list);

        // 删除指定位置的数据
        list.remove(1);
        list.remove("ddd");
        System.out.println(list);

        // 修改指定位置的数据
        list.set(1,"eee");
        System.out.println(list);
        
       // 获取指定位置的数据
        System.out.println(list.get(1));
    }
}

List集合的遍历方式

迭代器遍历

java 复制代码
public class demo {
    public static void main(String[] args) {
       List<String> list = new ArrayList<>();
       list.add("aaa");
       list.add("bbb");
       list.add("ccc");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            System.out.println(next);
        }
    }
}

列表迭代器遍历

java 复制代码
public class demo {
    public static void main(String[] args) {
       List<String> list = new ArrayList<>();
       list.add("aaa");
       list.add("bbb");
       list.add("ccc");
       //额外添加一个方法,可以添加元素
        ListIterator<String> it = list.listIterator();
        while (it.hasNext()) {
            String str = it.next();
            if("bbb".equals(str)) {
                it.add("qqq");
            }
        }
        System.out.println(list);
    }
}

增强for遍历

java 复制代码
public class demo {
    public static void main(String[] args) {
       List<String> list = new ArrayList<>();
       list.add("aaa");
       list.add("bbb");
       list.add("ccc");

        for (String s : list) {
            System.out.println(s);
        }
    }
}

Lambad表达式遍历

java 复制代码
public class demo {
    public static void main(String[] args) {
       List<String> list = new ArrayList<>();
       list.add("aaa");
       list.add("bbb");
       list.add("ccc");

       list.forEach(s->System.out.println(s));
    }
}

普通for循环

java 复制代码
public class demo {
    public static void main(String[] args) {
       List<String> list = new ArrayList<>();
       list.add("aaa");
       list.add("bbb");
       list.add("ccc");

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

数据结构

数据结构是计算机底层存储、组织数据的方式。是指数据之间是以什么样的方式排列在一起的。数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。

需要思考三问题:每种数据结构长什么样子?如何添加数据?数据删除数据?

常见的八种数据结构

  1. 栈 :先进后出、后进先出
  2. 队列:先进先出、后进后出
  3. 数组:查询快、数据在内存中连续存储;添加删除效率低,需要移动数据
  4. 链表:每个节点独立、查询慢、增删相对快
  5. 二叉树
  6. 二叉查找树
  7. 平衡二叉树
  8. 红黑树

红黑树

红黑树是一种自平衡的二叉查找树。红黑树是一种特殊的二叉查找树,每个节点都有存储位表示节点的颜色,每一个节点可以是红或者是黑,红黑树不是高度平衡的,它的平衡是通过红黑规则进行实现的。

红黑树规则

  1. 每个节点或是红色或是黑色
  2. 根结点必须是黑色
  3. 如果一个节点没有父节点或者子节点,那么该节点相应指针的属性值为Nil,这些Nil视为叶节点,每个叶节点是黑色的
  4. 如果一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点项链的情况)
  5. 对每一个节点,该节点到其所有后代叶节点的简单路径上,均包含相同数据的黑色节点。
红黑树添加规则

ArrayList集合

ArrayList集合底层原理

ArrayList底层是数组。

  • 利用空参创建的集合,在底层创建一个默认长度为0的数组。
  • 添加第一个元素时,底层会创建一个新的长度为10的数组,默认都是null。
  • 存满时,自动扩容1.5倍。
  • 如果一次添加多个元素,1.5倍放不下,则新创建的数组的长度以实际为准。

LinkedList集合

底层的数据结构是双向链表,查询慢,增删快,但是如果是操作首尾元素,速度也是很快的。

LinkedList集合独有的方法

泛型

泛型是JDK5中引入的特性,可以在变异阶段约束操作的数据类型,并进行检查。

泛型的格式:<数据类型> // 泛型只支持引用数据类型。

泛型的好处:

  • 统一数据类型;
  • 把运行时期的问题提前提前了编译期间,避免了强制类型转换出现的可能,因为在编译阶段类型就能确定下来。
    泛型的细节注意:
  • 泛型中不能写基本数据类型;
  • 指定具体类型后,传递数据时可以传入该类类型或者其子类类型;
  • 如果不写泛型,默认是Object。

泛型类

当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

修饰符 class 类名<类型>{

}

类型可以用E、T、K、V等替代,可以理解为变量。

泛型方法

方法中形参类型不确定时可以使用类面后面定义的泛型(所有的方法都能用)或者在方法申明上定义自己的泛型(只有本方法可以用)。

修饰符 <类型> 返回值类型 方法名 (类型 变量名){

}

java 复制代码
public <T> void show(T t){
}

泛型接口

修饰符 interface 接口名 <类型> {

}

java 复制代码
public interface List<E>{
}

Set集合

  1. 无序
  2. 不重复
  3. 无索引
    Set接口中方法基本与Collection的API一致。

HashSet集合

无序,不重复,无索引

HashSet底层采取哈希表存储数据,哈希表JDK8之前是数据+链表,JDK8开始是数据+链表+红黑树。

哈希值:对象的整数表现形式。根据hashCode方法计算出来的int类型的整数。需要重新写hashCode方法,利用对象内部的属性值计算哈希值。如果不重写,不同对象计算出的哈希值不同,如果重新写,不同对象只要属性值相同,计算出的哈希值就是一样的。

哈希表JDK8之前是数据+链表:

  1. 创建一个默认长度16,默认加载因子0.75的数组,数组名是table;
  2. 根据元素的哈希值跟数组长度计算应存入的位置。
  3. 判断是否是null,如果null直接添加
  4. 如果不是null,比较属性值,
  5. 一样:不存。 不一样:存入数组,形成链表。(JDK8之前,新元素存入数组,老元素挂在下面。JDK8以后,新元素直接挂在老元素下面,当链表长度超过8,数组长度大于等于64时,自动转为红黑树)

LinkedHashSet

有序,不重复,无索引

底层数据结构依然是哈希表,只是每个元素又额外多了一个双链表的机制记录存储的顺序。

TreeSet

不重复,无索引,可排序

可排序:默认从小到大排序。

Treeset底层基于红黑树的数据结构实现排序的,增删改查性能都比较好。

双列集合Map

Map常用的API

Map的遍历方式

键找值

java 复制代码
public class demo {
    public static void main(String[] args) {
       Map<String, String> map = new HashMap<>();
       map.put("1", "1111");
       map.put("2", "2222");
       map.put("3", "3333");
       
       //获取所有的键 放入单列集合
        Set<String> keys = map.keySet();
        for (String key : keys){
            System.out.println(key);
            //获取值
            System.out.println(map.get(key));
        }
    }
}

键值对

java 复制代码
public class demo {
    public static void main(String[] args) {
       Map<String, String> map = new HashMap<>();
       map.put("1", "1111");
       map.put("2", "2222");
       map.put("3", "3333");

       Set<Map.Entry<String, String>> entries = map.entrySet();
       for (Map.Entry<String, String> entry : entries) {
           System.out.println(entry.getKey() + ":" + entry.getValue());
       }

    }
}

Lambda表达式

java 复制代码
public class demo {
    public static void main(String[] args) {
       Map<String, String> map = new HashMap<>();
       map.put("1", "1111");
       map.put("2", "2222");
       map.put("3", "3333");

       map.forEach( (key,value) -> System.out.println(key + ":" + value));
    }
}

HashMap

  • HashMap是Map的一个实现类;
  • 没有额外的特有方法,直接使用Map里面的方法;
  • 特点都是由键觉定的:无序、不重复、无索引;
  • HashMap和HashSet的底层原理是一样的,都是哈希表结构。

LinkedHashMap

  • 由键决定:有序,不重复,无索引;
    底层数据结构依然是哈希表,只是每个元素又额外多了一个双链表的机制记录存储的顺序。

TreeMap

  • 跟TreeSet底层原理一样,都是红黑树结构的
  • 由键决定:不重复,无索引,可排序(默认从小到大,可以自定义)。

Collections

  • 是集合工具类
    常用的API:
相关推荐
海边的Kurisu18 分钟前
苍穹外卖日记 | Day1 苍穹外卖概述、开发环境搭建、接口文档
java
C雨后彩虹4 小时前
任务最优调度
java·数据结构·算法·华为·面试
heartbeat..4 小时前
Spring AOP 全面详解(通俗易懂 + 核心知识点 + 完整案例)
java·数据库·spring·aop
Jing_jing_X4 小时前
AI分析不同阶层思维 二:Spring 的事务在什么情况下会失效?
java·spring·架构·提升·薪资
SmartRadio5 小时前
CH585M+MK8000、DW1000 (UWB)+W25Q16的低功耗室内定位设计
c语言·开发语言·uwb
rfidunion6 小时前
QT5.7.0编译移植
开发语言·qt
rit84324996 小时前
MATLAB对组合巴克码抗干扰仿真的实现方案
开发语言·matlab
元Y亨H6 小时前
Nacos - 服务发现
java·微服务
微露清风6 小时前
系统性学习C++-第十八讲-封装红黑树实现myset与mymap
java·c++·学习
dasi02276 小时前
Java趣闻
java