学习笔记:黑马程序员Java-高级篇(第三部分)

Java语言入门到精通章节

  1. 学习笔记:Java-基础篇(第一部分)_ljtxy.love的博客-CSDN博客
  2. 学习笔记:Java-中级篇(第二部分)_ljtxy.love的博客-CSDN博客
  3. 学习笔记:Java-高级篇(第三部分)_ljtxy.love的博客-CSDN博客
  4. 学习笔记:Java-进阶篇(一)(第四部分)_ljtxy.love的博客-CSDN博客
  5. 学习笔记:Java-进阶篇(二)(第五部分)_ljtxy.love的博客-CSDN博客
  6. 学习笔记:Java8新特性_ljtxy.love的博客-CSDN博客

文章目录

17.集合类

笔记小结:见各个小节

17.1集合体系结构

笔记小结:

  1. 概述:集合分为单列集合与双列集合

    image-20230321141847845

  2. 特点:

    image-20230421090605057

  3. 单列集合:

    • List系列集合:有序可重复的集合
    • Set系列集合:无序不可重复的集合
    • 详细:见各个小结
  4. 双列集合:

    • HashMap: 基于哈希表实现,可以存储null键null值,不保证元素的顺序
    • TreeMap: 基于红黑树实现,按照键的自然顺序或者自定义的比较器排序,不允许有null键,但可以有null值
  5. 单列集合应用场景:

    image-20230421161119362

17.1.1概述

​ Java中的集合类是用于存储、操作和管理一组对象的容器。其中集合可分类为单列集合、双列集合

image-20230321141743728

​ 在 Java 中,单列集合指的是只能保存一个元素序列的集合,例如 List、Set 和 Queue 等。双列集合则指的是可以保存键值对的集合,例如 Map 等。单列集合和双列集合在保存和操作数据时的方式和目的有所不同

17.1.2单列集合

单列集合又分为:List系列集合、Set系列集合

image-20230321141847845

补充:

  • List系列集合:有序可重复的集合。可以通过索引来访问其中的元素,可以存储重复的元素
  • Set系列集合:无序不可重复的集合。不能通过索引来访问其中的元素,不可以存储重复的元素

17.1.3双列集合

​ Java中的双列集合是指可以存储键值对数据结构的集合,也称为映射表或关联数组

image-20230424194516589

补充:

  • 双列集合,一个键对应一个值
  • 键不可以重复,值可以重复

17.2Collection集合

笔记小结:

  1. 概述:Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的

  2. 常用成员方法;addclearremovecontainsisEmptysize

  3. 遍历方式

    • 迭代器:

      1. 概述:迭代器是集合专用的遍历方式,迭代器在遍历集合的时候是不依赖索引的

      2. 使用:迭代器需要掌握三个方法

        while (it.hasNext()) {
                   
                    
            String s = it.next(); 
            System.out.println(s);
        }
        
      3. 细节:

        1. 当迭代器中无元素或元素遍历完成,再次调用it.next()方法,则报错NoSuchElementException
      4. 迭代器遍历完毕,指针不会复位

        1. 循环中只能用一次next方法(因为next方法会做两件事,分别是获取元素和移动指针)
      5. 迭代器遍历时,不能用集合的方法进行增加或者删除,否则报错ConcurrentModificationException

  4. 原理:可参考知识加油站

  • 增强for循环:

    1. 概述:其内部原理是一个Iterator迭代器

    2. 格式:

         for(集合/数组中元素的数据类型 变量名 :  集合/数组名) {
               
               
         // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
         }
         //例如
         for(string s : list){
               
               
             System.out.println(s);
         }
      
    3. 注意:**修改增强for中的变量,不会改变集合中原本的数据,**因为是通过第三方变量进行赋值

  • Lambda表达式

    1. 概述:更简单、更直接的遍历集合的方式

    2. 格式:

         forEach(Consumer<? super T> action)
         //例如
         coll.forEach(s -> System.out.println(s));
      
    3. 底层原理:其实也会自己遍历集合,依次得到每一个元素。把得到的每一个元素,传递给下面的accept方法。s依次表示集合中的每一个数据

17.2.1概述

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

注意:

ollection是一个接口,我们不能直接创建他的对象。所以,现在我们学习他的方法时,只能创建他实现类的对象

17.2.2常用成员方法

方法名 说明
boolean add(E e) 添加元素
boolean remove(Object o) 从集合中移除指定的元素
boolean removeIf(Object o) 根据条件进行移除
void clear() 清空集合中的元素
boolean contains(Object o) 判断集合中是否存在指定的元素
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中元素的个数

17.2.2.1add()

Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
System.out.println(coll);
  • 如果我们要往List系列集合中添加数据,那么方法永远返回true,因为List系列的是允许元素重复的。
  • 如果我们要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功。如果当前要添加的元素已经存在,方法返回false,表示添加失败。 因为Set系列的集合不允许重复。

17.2.2.2clear()

Collection<String> coll = new ArrayList<>();
coll.clear();

17.2.2.3remove()

Collection<String> coll = new ArrayList<>();
System.out.println(coll.remove("aaa"));
System.out.println(coll);
  • 因为Collection里面定义的是共性的方法,所以此时不能通过索引进行删除。只能通过元素的对象进行删除。
  • 方法会有一个布尔类型的返回值,删除成功返回true,删除失败返回false
  • 如果要删除的元素不存在,就会删除失败。

17.2.2.4contains()

Collection<String> coll = new ArrayList<>(); 
boolean result1 = coll.contains("bbb");
System.out.println(result1);
  • 底层是依赖equals方法进行判断是否存在的
  • 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法。

17.2.2.5isEmpty()

Collection<String> coll = new ArrayList<>(); 
boolean result2 = coll.isEmpty();
System.out.println(result2);//false

17.2.2.6size()

Collection<String> coll = new ArrayList<>(); 
coll.add("ddd");
int size = coll.size();
System.out.println(size);//3

17.2.2.7案例–学生查询

//1.创建集合的对象
Collection<Student> coll = new ArrayList<>();

//2.创建三个学生对象
Student s1 = new Student("zhangsan",23);
Student s2 = new Student("lisi",24);
Student s3 = new Student("wangwu",25);


//3.把学生对象添加到集合当中
coll.add(s1);
coll.add(s2);
coll.add(s3);

//4.判断集合中某一个学生对象是否包含
Student s4 = new Student("zhangsan",23);
//因为contains方法在底层依赖equals方法判断对象是否一致的。
//如果存的是自定义对象,没有重写equals方法,那么默认使用Object类中的equals方法进行判断,而Object类中equals方法,依赖地址值进行判断。
//需求:如果同姓名和同年龄,就认为是同一个学生。
//所以,需要在自定义的Javabean类中,重写equals方法就可以了。
System.out.println(coll.contains(s4));

17.2.3遍历方式

17.2.3.1迭代器

概述:迭代器在Java中的类是Iterator,迭代器是集合专用的遍历方式

  • Collection集合获取迭代器

    image-20230420154333383

  • Iterator中的常用成员方法

    image-20230420154407344

代码示例:

public class IteratorDemo1 {
    
    
    public static void main(String[] args) {
    
    
        //创建集合对象
        Collection<String> c = new ArrayList<>();

        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("javaee");

        //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
        Iterator<String> it = c.iterator(); // 1.获取迭代器

        //用while循环改进元素的判断和获取
        while (it.hasNext()) {
    
     // 2.判断是否有元素
            String s = it.next(); // 3.获取元素 // 4.移动指针
            System.out.println(s);
        }
    }
}

说明:

迭代器运行流程:

  1. 创建指针
  2. 判断是否有元素
  3. 获取元素
  4. 移动指针

注意:

1,当迭代器中无元素或元素遍历完成,再次调用it.next()方法,则报错NoSuchElementException

2,迭代器遍历完毕,指针不会复位

3,循环中只能用一次next方法(因为next方法会做两件事,分别是获取元素和移动指针)

4,迭代器遍历时,不能用集合的方法进行增加或者删除,否则报错ConcurrentModificationException

迭代器删除

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

示例:

public class IteratorDemo2 {
    
    
    public static void main(String[] args) {
    
    
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        list.add("d");

        Iterator<String> it = list.iterator();
        while(it.hasNext()){
    
    
            String s = it.next();
            if("b".equals(s)){
    
    
                //指向谁,那么此时就删除谁.
                it.remove();
            }
        }
        System.out.println(list);
    }
}

注意:

迭代器遍历时,不能用集合的方法进行增加或者删除,否则报错ConcurrentModificationException

17.2.3.2增强for循环

格式:

for(集合/数组中元素的数据类型 变量名 :  集合/数组名) {
    
    
// 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
}
//例如
for(string s : list){
    
    
    System.out.println(s);
}

示例:

public class MyCollectonDemo1 {
    
    
    public static void main(String[] args) {
    
    
        ArrayList<String> list =  new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        list.add("f");

        //1,数据类型一定是集合或者数组中元素的类型
        //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素
        //3,list就是要遍历的集合或者数组
        for(String str : list){
    
    
            System.out.println(str);
        }
    }
}

注意:

**修改增强for中的变量,不会改变集合中原本的数据,**因为是通过第三方变量进行赋值

image-20230420160153625

17.2.3.3Lambda表达式

概述:得益于JDK8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。

常用成员方法:

image-20230420160321849

示例:

Collection<String> coll = new ArrayList<>();
coll.add("zhangsan");
coll.add("lisi");
coll.add("wangwu");
coll.forEach(s -> System.out.println(s));

注意:

底层原理:其实也会自己遍历集合,依次得到每一个元素。把得到的每一个元素,传递给下面的accept方法。s依次表示集合中的每一个数据

image-20230420160647933

17.3List集合

笔记小结:

  1. 概述:List是Java中常用的集合类型之一,用于存储有序、可重复的元素序列

  2. 常用成员方法:addremovesetget

  3. 遍历方式:参见Collection集合遍历方式

    image-20230328210559638

17.3.1概述

image-20230420161417186

​ Collection的方法List都继承了集合的方法列表都继承了,List集合因为有索引,所以多了很多索引操作的方法。列出集合因为有索引,所以多了很多索引操作的方法。

  • 有序集合,这里的有序指的是存取顺序
  • 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
  • 与Set集合不同,列表通常允许重复的元素

特点

  • 存取有序
  • 可以重复
  • 索引

17.3.2常用成员方法

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

17.3.2.1add()

List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");//1
list.add("ccc");
// 或者
list.add(1,"QQQ") // 在此集合中的指定位置插入指定的元素

注意:

原来索引上的元素会依次往后移

17.3.2.2remove()

List<String> list = new ArrayList<>();
String remove = list.remove(0); //删除指定索引处的元素,返回被删除的元素
System.out.println(remove);//aaa

17.3.2.3set()

List<String> list = new ArrayList<>();
String result = list.set(0, "QQQ"); //修改指定索引处的元素,返回被修改的元素
System.out.println(result);

17.3.2.4get()

List<String> list = new ArrayList<>();
String s = list.get(0); //返回指定索引处的元素
System.out.println(s);

17.3.2.5案例–基础操作

public class MyListDemo {
    
    
    public static void main(String[] args) {
    
    
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        //method1(list);
        //method2(list);
        //method3(list);
        //method4(list);
    }

    private static void method4(List<String> list) {
    
    
        //        E get(int index)		返回指定索引处的元素
        String s = list.get(0);
        System.out.println(s);
    }

    private static void method3(List<String> list) {
    
    
        //        E set(int index,E element)	修改指定索引处的元素,返回被修改的元素
        //被替换的那个元素,在集合中就不存在了.
        String result = list.set(0, "qqq");
        System.out.println(result);
        System.out.println(list);
    }

    private static void method2(List<String> list) {
    
    
        //        E remove(int index)		删除指定索引处的元素,返回被删除的元素
        //在List集合中有两个删除的方法
        //第一个 删除指定的元素,返回值表示当前元素是否删除成功
        //第二个 删除指定索引的元素,返回值表示实际删除的元素
        String s = list.remove(0);
        System.out.println(s);
        System.out.println(list);
    }

    private static void method1(List<String> list) {
    
    
        //        void add(int index,E element)	在此集合中的指定位置插入指定的元素
        //原来位置上的元素往后挪一个索引.
        list.add(0,"qqq");
        System.out.println(list);
    }
}

17.3.3遍历方式

说明:此遍历方式,参考Collection集合遍历方式

image-20230328210559638

基本用例

package com.itheima.a02mylist;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class A03_ListDemo3 {
    
    
    public static void main(String[] args) {
    
    
        /*
            List系列集合的五种遍历方式:
                1.迭代器
                2.列表迭代器
                3.增强for
                4.Lambda表达式
                5.普通for循环
         */


        //创建集合并添加元素
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        //1.迭代器
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
    
    
            String str = it.next();
            System.out.println(str);
        }


        //2.增强for
        //下面的变量s,其实就是一个第三方的变量而已。
        //在循环的过程中,依次表示集合中的每一个元素
       for (String s : list) {
    
    
            System.out.println(s);
        }

        //3.Lambda表达式
        //forEach方法的底层其实就是一个循环遍历,依次得到集合中的每一个元素
        //并把每一个元素传递给下面的accept方法
        //accept方法的形参s,依次表示集合中的每一个元素
        list.forEach(s->System.out.println(s) );


        //4.普通for循环
        //size方法跟get方法还有循环结合的方式,利用索引获取到集合中的每一个元素
        for (int i = 0; i < list.size(); i++) {
    
    
            //i:依次表示集合中的每一个索引
            String s = list.get(i);
            System.out.println(s);
        }

        // 5.列表迭代器
        //获取一个列表迭代器的对象,里面的指针默认也是指向0索引的

        //额外添加了一个方法:在遍历的过程中,可以添加元素
        ListIterator<String> it = list.listIterator();
        while(it.hasNext()){
    
    
            String str = it.next();
            if("bbb".equals(str)){
    
    
                //qqq
                it.add("qqq");
            }
        }
        System.out.println(list);
    }
}

17.4ArrayList集合

笔记小结:

  1. 概述;ArrayList是Java中的一个类,它实现了List接口,是一种基于动态数组实现的集合类
  2. 常用成员方法:
    • 构造方法:ArrayList()
    • 成员方法:addremovesetgetsize
  3. 底层原理:
    • 利用空参创建的集合,在底层创建一个默认长度为0的数组
    • 添加第一个元素时,底层会创建一个新的长度为10的数组存满时,会扩容1.5倍
    • 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

17.4.1概述

  • 什么是集合

    ​ 提供一种存储空间可变的存储模型,存储的数据容量可以发生改变

  • ArrayList集合的特点

    ​ 长度可以变化,只能存储引用数据类型。

  • 泛型的使用

    ​ 用于约束集合中存储元素的数据类型

17.4.2常用成员方法

17.4.2.1构造方法

方法名 说明
public ArrayList() 创建一个空的集合对象

17.4.2.2成员方法

方法名 说明
public boolean add(要添加的元素) 将指定的元素追加到此集合的末尾
public boolean remove(要删除的元素) 删除指定元素,返回值表示是否删除成功
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中的元素的个数

示例:

public class ArrayListDemo02 {
    
    
    public static void main(String[] args) {
    
    
        //创建集合
        ArrayList<String> array = new ArrayList<String>();

        //添加元素
        array.add("hello");
        array.add("world");
        array.add("java");

        //public boolean remove(Object o):删除指定的元素,返回删除是否成功
        //        System.out.println(array.remove("world"));
        //        System.out.println(array.remove("javaee"));

        //public E remove(int index):删除指定索引处的元素,返回被删除的元素
        //        System.out.println(array.remove(1));

        //IndexOutOfBoundsException
        //        System.out.println(array.remove(3));

        //public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
        //        System.out.println(array.set(1,"javaee"));

        //IndexOutOfBoundsException
        //        System.out.println(array.set(3,"javaee"));

        //public E get(int index):返回指定索引处的元素
        //        System.out.println(array.get(0));
        //        System.out.println(array.get(1));
        //        System.out.println(array.get(2));
        //System.out.println(array.get(3)); //?????? 自己测试

        //public int size():返回集合中的元素的个数
        System.out.println(array.size());

        //输出集合
        System.out.println("array:" + array);
    }
}

17.4.3底层原理

image-20230328211534089

说明:

  • 当长度为m(m<=10)的数组,添加少于n(n<10)个元素时,底层实际数组长度为10

  • 当长度为m(m<=10)的数组,添加多余n(n>10)个元素时,底层实际长度为n+10

  • 当长度为m(m>10)的数组,添加少于n(n<10)个元素时,底层实际数组长度为m*1.5

  • 当长度为m(m>10)的数组,添加多余n(n>10)个元素时,底层实际数组长度为m+n

源码分析:

transient Object[] elementData; // non-private to simplify nested class access

ArrayList底层是一个数组

添加一个元素

image-20230329090130680

添加十个元素

image-20230329090105856

17.5LinkedList集合

笔记小结:

  1. 概述:LinkedList是Java集合框架中的一个双向链表实现类,可以用来存储一组有序的元素。LinkedList本身多了很多直接操作首尾元素的特有API
  2. 常用成员方法:addFirstaddLastgetFirstgetLastremoveFirstremoveLast
  3. 底层原理:底层数据结构是双链表查询慢,增删快,但是如果操作的是首尾元素速度也是极的。

17.5.1概述

​ LinkedList是Java集合框架中的一个双向链表实现类,可以用来存储一组有序的元素。LinkedList的元素是通过链表连接在一起的,每个元素都包含了一个指向前一个元素和后一个元素的引用。因此,插入和删除元素的时间复杂度是O(1)的,而随机访问元素的时**间复杂度是O(n)**的,其中n是LinkedList中元素的个数。

17.5.2常用成员方法

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

示例:

public class MyLinkedListDemo4 {
    
    
    public static void main(String[] args) {
    
    
        LinkedList<String> list = new LinkedList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
//        public void addFirst(E e)	在该列表开头插入指定的元素
        //method1(list);

//        public void addLast(E e)	将指定的元素追加到此列表的末尾
        //method2(list);

//        public E getFirst()		返回此列表中的第一个元素
//        public E getLast()		返回此列表中的最后一个元素
        //method3(list);

//        public E removeFirst()		从此列表中删除并返回第一个元素
//        public E removeLast()		从此列表中删除并返回最后一个元素
        //method4(list);
      
    }

    private static void method4(LinkedList<String> list) {
    
    
        String first = list.removeFirst();
        System.out.println(first);

        String last = list.removeLast();
        System.out.println(last);

        System.out.println(list);
    }

    private static void method3(LinkedList<String> list) {
    
    
        String first = list.getFirst();
        String last = list.getLast();
        System.out.println(first);
        System.out.println(last);
    }

    private static void method2(LinkedList<String> list) {
    
    
        list.addLast("www");
        System.out.println(list);
    }

    private static void method1(LinkedList<String> list) {
    
    
        list.addFirst("qqq");
        System.out.println(list);
    }
}

17.5.3底层原理

image-20230420183312596

说明:

当添加第1个元素时,会将头结点和尾结点指向第1个元素,并且第1元素的前索引和后索引都为空

image-20230420184549301

说明:

当添加第n个元素时,会将尾结点指向第n个元素,并且第n个元素前索引为n-1,第n个元素后索引为空

17.6Set集合

笔记小结:

  1. 概述:它用于存储不重复的元素

  2. 常用成员方法:

    方法名 说明
    boolean add(E e) 添加元素
    boolean remove(Object o) 从集合中移除指定的元素
    boolean removeIf(Object o) 根据条件进行移除
    void clear() 清空集合中的元素
    boolean contains(Object o) 判断集合中是否存在指定的元素
    boolean isEmpty() 判断集合是否为空
    int size() 集合的长度,也就是集合中元素的个数
  3. 遍历方式:

    image-20230328210559638

17.6.1概述

Set集合是Java集合框架中的一种,它用于存储不重复的元素,具有无序性。

特点:

  • 无序:存取顺序不一致
  • 不重复:可以去除重复
  • 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素

17.6.2常用成员方法

方法名 说明
boolean add(E e) 添加元素
boolean remove(Object o) 从集合中移除指定的元素
boolean removeIf(Object o) 根据条件进行移除
void clear() 清空集合中的元素
boolean contains(Object o) 判断集合中是否存在指定的元素
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中元素的个数

说明:

​ Set集合的方法基本上雨Collection的API一致

17.6.3遍历方式

此遍历方式,参考Collection集合遍历方式

image-20230328210559638

示例:

public class A01_SetDemo1 {
    
    
    public static void main(String[] args) {
    
    
       /*
           利用Set系列的集合,添加字符串,并使用多种方式遍历。
            迭代器
            增强for
            Lambda表达式

        */


        //1.创建一个Set集合的对象
        Set<String> s = new HashSet<>();

        //2,添加元素
        //如果当前元素是第一次添加,那么可以添加成功,返回true
        //如果当前元素是第二次添加,那么添加失败,返回false
        s.add("张三");
        s.add("张三");
        s.add("李四");
        s.add("王五");

        //3.打印集合
        //无序
        System.out.println(s);//[李四, 张三, 王五]

        //迭代器遍历
      Iterator<String> it = s.iterator();
        while (it.hasNext()){
    
    
            String str = it.next();
            System.out.println(str);
        }


        //增强for
       for (String str : s) {
    
    
            System.out.println(str);
        }

        // Lambda表达式
        s.forEach( str->System.out.println(str));


    }
}

17.7HashSet集合

笔记小结:

  1. 概述:它是基于哈希表实现的,可以存储无序的不重复的元素
  2. 底层原理:
    • HashSet集合底层采取哈希表存储数据
    • 哈希表是一种对于增删改查数据性能都较好的结构
  3. HashSet的三个问题;
    1. HashSet为什么存和取的顺序不一样?
      • 答案:链表中添加的数据不是按照指定的顺序存储的,数据在链表中的添加顺序不同,因此存和取的顺序不一样。
    2. HashSet为什么没有索引?
      • 答案:HashSet底层是由数组、链表、红黑树组成。此时,在1索引的位置下挂着一个链表,如此多的元素都为1索引,看起来不合适,因此就取消掉了索引的机制
    3. HashSet是利用什么机制保证数据去重的?
      • 答案:HashSet是根据HashCodeequals方法,进行判断元素是否相同

17.7.1概述

哈希值

  • 含义:对象的整数表现形式

    image-20230811231656961

  • 概述:

    • 根据hashCode方法算出来的int类型的整数
    • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
    • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

对象的哈希值特点:

  • 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的

    image-20230421110116935

  • 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的

    image-20230421110409579

  • 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)

    image-20230421110529071

    int的取值范围用将近42亿中,如果此时创建50亿个对象,就有可能8亿hash值相同

示例:

        //1.创建对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("zhangsan",23);

        //2.如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
        //  如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
        System.out.println(s1.hashCode());//-1461067292
        System.out.println(s2.hashCode());//-1461067292


        //在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。
        //哈希碰撞
        System.out.println("abc".hashCode());//96354
        System.out.println("acD".hashCode());//96354

17.7.2底层原理

HashSet底层原理

  • HashSet集合底层采取哈希表存储数据
  • 哈希表是一种对于增删改查数据性能都较好的结构

哈希表组成

  • JDK8之前:数组+链表
  • JDK8开始:数组+链表+红黑树

JDK1.8以前:

image-20230811230228107

JDK1.8以后:

  • 节点个数少于等于8个

    ​ 数组 + 链表

  • 节点个数多于8个

    ​ 数组 + 红黑树

image-20230811225123292

说明:

加载因子:又叫HashSet的扩容时机

当数组内存储了16x0.75 = 12个元素时,次数数组的长度会扩容到原来的两倍,也就是32

当链表长度大于8而且数组长度大于等于64,链表就会转换为红黑树

底层流程:

image-20230421112253380

image-20230421112312925

17.7.3HashSet的三个问题

image-20230421112454766

说明:

​ 当遍历数组时,下标为1索引时,存储为链表。链表中添加的数据不是按照指定的顺序存储的,数据在链表中的添加顺序不同,因此存和取的顺序不一样。HashSet的存储索引是 通过hashCode方法算出来的int类型的整数。

image-20230421112904950

说明:

​ HashSet底层是又数组、链表、红黑树组成。此时,在1索引的位置下挂着一个链表,如此多的元素都为1索引,看起来不合适,因此就取消掉了索引的机制

image-20230421113123565

说明:

​ HashSet是根据HashCode和equals方法,进行判断元素是否相同,若相同则不会添加到数组、链表或者红黑树当中。因此,在像HashSet中添加自定义对象是,一定要记得重写HashCode和equals方法,让底层的Hash值是根据对象的属性来生成

示例:

public class HashSetDemo02 {
    
    
    public static void main(String[] args) {
    
    
        //创建HashSet集合对象
        HashSet<Student> hs = new HashSet<Student>();

        //创建学生对象
        Student s1 = new Student("林青霞", 30);
        Student s2 = new Student("张曼玉", 35);
        Student s3 = new Student("王祖贤", 33);

        Student s4 = new Student("王祖贤", 33);

        //把学生添加到集合
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);

        //遍历集合(增强for)
        for (Student s : hs) {
    
    
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

注意:

​ HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法

@Override
 public boolean equals(Object o) {
     
     
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;

     Student student = (Student) o;

     if (age != student.age) return false;
     return name != null ? name.equals(student.name) : student.name == null;
 }

 @Override
 public int hashCode() {
     
     
     int result = name != null ? name.hashCode() : 0;
     result = 31 * result + age;
     return result;
 }

Idea中重写,可Alt+Insert进行快捷重写

17.8LinkedHashSet集合

笔记小结:

  1. 概述:LinkedHashSetHashSet 的一个子类,它使用了一个双向链表来维护插入顺序,同时也保持了 HashSet 的元素唯一性
  2. 特点:有序、不重复、无索引。
  3. 底层原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储顺序

17.8.1概述

17.8.2底层原理

  • 有序、不重复、无索引。
  • 这里的有序指的是保证存储和取出的元素顺序一致
  • 原理∶底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。

image-20230421114431793

示例:

public class A04_LinkedHashSetDemo {
    
    
    public static void main(String[] args) {
    
    
        //1.创建4个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("zhangsan",23);


        //2.创建集合的对象
        LinkedHashSet<Student> lhs = new LinkedHashSet<>();


        //3.添加元素
        System.out.println(lhs.add(s3));
        System.out.println(lhs.add(s2));
        System.out.println(lhs.add(s1));
        System.out.println(lhs.add(s4));

        //4.打印集合
        System.out.println(lhs);
    }
}

说明:

​ LinkedHashSet存入和取出的数据是有序的

17.9TreeSet集合

笔记小节:

  1. 概述:TreeSet 是 Java 集合框架中的一个集合类,它实现了 SortedSet 接口,可以对元素进行排序
  2. 底层原理:TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
  3. 两种比较方式:默认排序/自然排序、比较器排序
  4. 细节:比较方式使用原则:默认使用第一种,如果第一种不能满足当前需求,就使用第二种,自定义排序

17.9.1概述

特点:

  • 不重复、无索引、可排序
  • 可排序:按照元素的默认规则(有小到大)排序
  • TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好

TreeSet集合默认的规则:

  • 对于数值类型:Integer , Double,默认按照从小到大的顺序进行排序。
  • 对于字符、字符串类型:按照字符在ASClI码表中的数字升序进行排序。

17.9.2常用成员方法

类是于Set

基础示例:

 //1.创建TreeSet集合对象
        TreeSet<Integer> ts = new TreeSet<>();

        //2.添加元素
        ts.add(4);
        ts.add(5);
        ts.add(1);
        ts.add(3);
        ts.add(2);

        //3.打印集合
        //System.out.println(ts);

        //4.遍历集合(三种遍历)
        //迭代器
        Iterator<Integer> it = ts.iterator();
        while(it.hasNext()){
    
    
            int i = it.next();
            System.out.println(i);
        }

        System.out.println("--------------------------");
        //增强for
        for (int t : ts) {
    
    
            System.out.println(t);
        }
        System.out.println("--------------------------");
        //lambda
        ts.forEach( i-> System.out.println(i));

17.9.3两种排序比较方式

17.9.3.1默认排序/自然排序

Javabean类实现Comparable接口指定比较规则

public class Student implements Comparable<Student>{
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
    
    
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
    
    
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
    
    
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String toString() {
    
    
        return "Student{name = " + name + ", age = " + age + "}";
    }

    @Override
    //this:表示当前要添加的元素
    //o:表示已经在红黑树存在的元素

    //返回值:
    //负数:表示当前要添加的元素是小的,存左边
    //正数:表示当前要添加的元素是大的,存右边
    //0 :表示当前要添加的元素已经存在,舍弃
    public int compareTo(Student o) {
    
    
        System.out.println("--------------");
        System.out.println("this:" + this);
        System.out.println("o:" + o);
        //指定排序的规则
        //只看年龄,我想要按照年龄的升序进行排列
        return this.getAge() - o.getAge();
    }
}

说明:

若需要将此类用于Treeset,需要实现Comparable接口,并在实现时指定泛型的类

public class A05_TreeSetDemo2 {
    
    
    public static void main(String[] args) {
    
    
        /*
            需求:创建TreeSet集合,并添加3个学生对象
            学生对象属性:
                姓名,年龄。
                要求按照学生的年龄进行排序
                同年龄按照姓名字母排列(暂不考虑中文)
                同姓名,同年龄认为是同一个人

            方式一:
                默认的排序规则/自然排序
                Student实现Comparable接口,重写里面的抽象方法,再指定比较规则
        */


        //1.创建三个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("zhaoliu",26);


        //2.创建集合对象
        TreeSet<Student> ts = new TreeSet<>();

        //3.添加元素
        ts.add(s3);
        ts.add(s2);
        ts.add(s1);
        ts.add(s4);

        //4.打印集合
        System.out.println(ts);


        //TreeSet 底层是红黑树

    }
}

17.9.3底层原理:

image-20230421154711618

17.9.3.2比较器排序

创建TreeSet对象时候,传递比较器Comparator指定规则

public class A06_TreeSetDemo3 {
    
    
    public static void main(String[] args) {
    
    
       /*
            需求:请自行选择比较器排序和自然排序两种方式;
            要求:存入四个字符串, “c”, “ab”, “df”, “qwer”
            按照长度排序,如果一样长则按照首字母排序

            采取第二种排序方式:比较器排序
        */

        //1.创建集合
        //o1:表示当前要添加的元素
        //o2:表示已经在红黑树存在的元素
        //返回值规则跟之前是一样的
        TreeSet<String> ts = new TreeSet<>((o1, o2)->{
    
    
                // 按照长度排序
                int i = o1.length() - o2.length();
                //如果一样长则按照首字母排序
                i = i == 0 ? o1.compareTo(o2) : i;
                return i;
        });

        //2.添加元素
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");


        //3.打印集合
        System.out.println(ts);


    }
}

17.9.4方法返回值特点

  • 负数:表示当前要添加的元素是小的,存左边
  • 正数:表示当前要添加的元素是大的,存右边
  • 0:表示当前要添加的元素已经存在,舍弃

17.10单列集合应用场景(重点)

image-20230421161119362

17.11Map集合

笔记小结:

  1. 概述:Map 是一种用于存储键值对的集合,每个键对应一个唯一的

  2. 常用成员方法:putremoveclearcontainsKeycontainsValueisEmptysize.

  3. 遍历方式:

    • 键找值,API:map.keySet()

      Set<String> keys = map.keySet();
      for (String key : keys) {
               
               
          String value = map.get(key);
      }
      
    • 键值对,API:map.entrySet()

      Set<Map.Entry<String, String>> entries = map.entrySet();
      for (Map.Entry<String, String> entry : entries) {
               
               
          String key = entry.getKey();
          String value = entry.getValue();
      }
      
    • Lambda表达式,API:map.forEach()

      map.forEach(new BiConsumer<String, String>() {
               
               
          @Override
          public void accept(String key, String value) {
               
               
              System.out.println(key + "=" + value);
          }
      });
      

17.11.1概述

​ 在 Java 中,Map 是一种用于存储键值对的集合,每个键对应一个唯一的值。它是一种非常常用的集合,可用于快速查找和访问数据。

格式:

interface Map<K,V>  K:键的类型;V:值的类型

17.11.2常用成员方法

方法名 说明
V put(K key,V value) 添加元素
V remove(Object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(Object key) 判断集合是否包含指定的键
boolean containsValue(Object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数

17.11.2.1put()

Map<String,String> map = new HashMap<String,String>();
map.put("张无忌","赵敏");
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
  • 在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
  • 在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把返回被覆盖的值

17.11.2.2clear()

Map<String,String> map = new HashMap<String,String>();
map.clear();

17.11.2.3remove()

Map<String,String> map = new HashMap<String,String>();    
String result = map.remove("郭靖"); 
  • 在删除数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回null
  • 在删除数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把返回被删除的值

17.11.2.4containsKey()

Map<String,String> map = new HashMap<String,String>();    
boolean keyResult = m.containsKey("郭靖");
System.out.println(valueResult);

17.11.2.5containsValue()

Map<String,String> map = new HashMap<String,String>();    
boolean valueResult = map.containsValue("小龙女2");
System.out.println(valueResult);

17.11.2.6isEmpty()

Map<String,String> map = new HashMap<String,String>();    
boolean result = map.isEmpty();
System.out.println(result);

17.11.2.7size()

Map<String,String> map = new HashMap<String,String>();   
int size = map.size();
System.out.println(size);

17.11.2.8案例–神话人物查询

public class MapDemo02 {
    
    
    public static void main(String[] args) {
    
    
        //创建集合对象
        Map<String,String> map = new HashMap<String,String>();

        //V put(K key,V value):添加元素
        map.put("张无忌","赵敏");
        map.put("郭靖","黄蓉");
        map.put("杨过","小龙女");

        //V remove(Object key):根据键删除键值对元素
//        System.out.println(map.remove("郭靖"));
//        System.out.println(map.remove("郭襄"));

        //void clear():移除所有的键值对元素
//        map.clear();

        //boolean containsKey(Object key):判断集合是否包含指定的键
//        System.out.println(map.containsKey("郭靖"));
//        System.out.println(map.containsKey("郭襄"));

        //boolean isEmpty():判断集合是否为空
//        System.out.println(map.isEmpty());

        //int size():集合的长度,也就是集合中键值对的个数
        System.out.println(map.size());

        //输出集合对象
        System.out.println(map);
    }
}

17.11.3遍历方式

17.11.3.1键找值

概述:通过Map集合的键来获得值

方法介绍:

方法名 说明
V get(Object key) 根据键获取值
Set keySet() 获取所有键的集合
Collection values() 获取所有值的集合

基本用例:

public class MapDemo01 {
    
    
    public static void main(String[] args) {
    
    
        //1.创建Map集合的对象
        Map<String,String> map = new HashMap<>();

        //2.添加元素
        map.put("尹志平","小龙女");
        map.put("郭靖","穆念慈");
        map.put("欧阳克","黄蓉");

        //3.通过键找值

        //3.1获取所有的键,把这些键放到一个单列集合当中
        Set<String> keys = map.keySet();
        //3.2遍历单列集合,得到每一个键
        for (String key : keys) {
    
    
            //System.out.println(key);
            //3.3 利用map集合中的键获取对应的值  get
            String value = map.get(key);
            System.out.println(key + " = " + value);
        }
        //4.直接找值
        Collection<String> values = map.values();
        for(String value : values) {
    
    
            System.out.println(value);
        }
    }
}

17.11.3.2键值对

概述:通过Map集合获取键值对

方法介绍:

方法名 说明
Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合

基本用例:

public class MapDemo03 {
    
    
    public static void main(String[] args) {
    
    
        //Map集合的第二种遍历方式
        
        //1.创建Map集合的对象
        Map<String, String> map = new HashMap<>();

        //2.添加元素
        //键:人物的外号
        //值:人物的名字
        map.put("标枪选手", "马超");
        map.put("人物挂件", "明世隐");
        map.put("御龙骑士", "尹志平");

        //3.Map集合的第二种遍历方式
        //通过键值对对象进行遍历
        //3.1 通过一个方法获取所有的键值对对象,返回一个Set集合
        Set<Map.Entry<String, String>> entries = map.entrySet();
        //3.2 遍历entries这个集合,去得到里面的每一个键值对对象
        for (Map.Entry<String, String> entry : entries) {
    
    //entry  --->  "御龙骑士","尹志平"
            //3.3 利用entry调用get方法获取键和值
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }
    }
}

17.11.3.3Lambda表达式

概述:得益于JDK8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。

基本用例:

public class MapDemo03 {
    
    
    public static void main(String[] args) {
    
    
       //Map集合的第三种遍历方式


        //1.创建Map集合的对象
        Map<String,String> map = new HashMap<>();

        //2.添加元素
        //键:人物的名字
        //值:名人名言
        map.put("鲁迅","这句话是我说的");
        map.put("曹操","不可能绝对不可能");
        map.put("刘备","接着奏乐接着舞");
        map.put("柯镇恶","看我眼色行事");

        //3.利用lambda表达式进行遍历
        //底层:
        //forEach其实就是利用第二种方式进行遍历,依次得到每一个键和值
        //再调用accept方法
        map.forEach(new BiConsumer<String, String>() {
    
    
            @Override
            public void accept(String key, String value) {
    
    
                System.out.println(key + "=" + value);
            }
        });

        System.out.println("-----------------------------------");

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

        System.out.println("-----------------------------------");

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

    }
}

17.12HashMap集合

笔记小结:

  1. 概述:HashMap 是 Java 中的一个集合类,它实现了 Map 接口,可以用来存储键值对
  2. 特点:无序的、 允许使用 null 作为键或值、键是唯一的,插入键相同则覆盖线程不安全的、HashMap 的实现是基于哈希表的,使用哈希算法来确定键值对的存储位置,因此插入和查询时间复杂度为 O(1)
  3. 底层原理:
    • HashMap底层是哈希表结构
    • 依赖hashCode方法和equals方法保证键的唯一
    • 如果要存储的是自定义对象需要重写hashCode和equals方法(此处注意!!!!)。如果要存储的是自定义对象,不需要重写hashCode和equals方法0
    • 待完善,详细参见视频!!!

17.12.1概述

image-20230424195034363

HashMap 是 Java 中的一个集合类,它实现了 Map 接口,可以用来存储键值对。

特点:

  • HashMap 中的键值对是无序的。
  • HashMap 允许使用 null 作为键或值。
  • HashMap 的键是唯一的,如果插入了两个相同的键,则后插入的值会覆盖先插入的值。
  • HashMap 是线程不安全的,如果多个线程同时对 HashMap 进行操作,可能会导致数据不一致。
  • HashMap 的实现是基于哈希表的,使用哈希算法来确定键值对的存储位置,因此插入和查询的时间复杂度为 O(1)。

基本用例:

public class HashMapDemo {
    
    
    public static void main(String[] args) {
    
    
        //创建HashMap集合对象
        HashMap<Student, String> hm = new HashMap<Student, String>();

        //创建学生对象
        Student s1 = new Student("林青霞", 30);
        Student s2 = new Student("张曼玉", 35);
        Student s3 = new Student("王祖贤", 33);
        Student s4 = new Student("王祖贤 ", 33);

        //把学生添加到集合
        hm.put(s1, "西安");
        hm.put(s2, "武汉");
        hm.put(s3, "郑州");
        hm.put(s4, "北京");

        //遍历集合
        Set<Student> keySet = hm.keySet();
        for (Student key : keySet) {
    
    
            String value = hm.get(key);
            System.out.println(key.getName() + "," + key.getAge() + "," + value);
        }
    }
}

17.12.2底层原理

image-20230424204844400

说明:

此图为HashMap底层源码的改写版本,通俗易懂

image-20230811225217966

  • HashMap底层是哈希表结构的
  • 依赖hashCode方法和equals方法保证键的唯一
  • 如果要存储的是自定义对象,需要重写hashCode和equals方法。如果要存储的是自定义对象,不需要重写hashCode和equals方法0

参考资料:集合进阶-13-HashMap源码超详细解析(一)_哔哩哔哩_bilibili

17.13LinkedHashMap集合

笔记小结:

  1. 概述:LinkedHashMap 是 HashMap 的一个子类
  2. 特点:不重复无索引有序性
  3. 底层原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。跟HashSet一样

17.13.1概述

image-20230424195741868

LinkedHashMap 是 HashMap 的一个子类

特点:

  • 不重复
  • 无索引
  • 有序性:LinkedHashMap 中的元素按照插入顺序排序,也可以按照访问顺序排序(通过构造函数传入 accessOrder 参数为 true 实现)。

17.13.2底层原理

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

17.14TreeMap集合

笔记小结:

  1. 概述:TreeMap 是 Java 中的一种双列集合,它基于红黑树实现。TreeMap 通过 key-value 存储数据,支持根据 key 值进行排序和查找,可以保证元素有序,因此在需要对集合中的元素进行排序时,可以使用 TreeMap。

  2. 特点:

    • TreeMap底层是红黑树结构
    • 依赖自然排序或者比较器排序,对键进行排序
    • 如果存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
    • 注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
  3. 底层原理:待完善,详细参见视频!!!

17.14.1概述

特点:

  • TreeMap底层是红黑树结构
  • 依赖自然排序或者比较器排序,对键进行排序
  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
  • 注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则

基本用例:

public class Test1 {
    
    
    public static void main(String[] args) {
    
    
      	// 创建TreeMap集合对象
        TreeMap<Student,String> tm = new TreeMap<>();
      
		// 创建学生对象
        Student s1 = new Student("xiaohei",23);
        Student s2 = new Student("dapang",22);
        Student s3 = new Student("xiaomei",22);
      
		// 将学生对象添加到TreeMap集合中
        tm.put(s1,"江苏");
        tm.put(s2,"北京");
        tm.put(s3,"天津");
      
		// 遍历TreeMap集合,打印每个学生的信息
        tm.forEach(
                (Student key, String value)->{
    
    
                    System.out.println(key + "---" + value);
                }
        );
    }
}

也需要在student类中进行接口实现

public class Student implements Comparable<Student>{
    
    
	……………………
    @Override
    public int compareTo(Student o) {
    
    
        //按照年龄进行排序
        int result = o.getAge() - this.getAge();
        //次要条件,按照姓名排序。
        result = result == 0 ? o.getName().compareTo(this.getName()) : result;
        return result;
    }
}

17.14.2底层原理

参考资料:集合进阶-17-TreeMap源码超详细解析(一)_哔哩哔哩_bilibili

17.15不可变集合

笔记小结:

  1. 概述:是一个长度不可变内容无法修改的集合

  2. 特点:定义完成后

    • 不可修改
    • 不可添加
    • 不可删除
  3. 常用成员方法:List、Set、Map接口中,都存在of方法可以创建不可变集合

  4. 三种方式的细节:

    1. List:直接用

       List<String> list = List.of("张三", "李四", "王五", "赵六");
      
    2. Set:元素不能重复

       Set<String> set = Set.of("张三", "张三", "李四", "王五", "赵六");
      
    3. Map:元素不能重复、键值对数量最多是10个。

      • 少于10个用of方法

            Map<String, String> map = Map.of("张三", "南京", "张三",……);
        
      • 超过10个用ofEntries方法

           HashMap<String, String> hm = new HashMap<>();
        hm.put("张三", "南京");
        hm.put("李四", "北京");
        Map<String, String> map = Map.copyOf(hm); // 此方法为JDK10之后才拥有的
        

17.15.1概述

是一个长度不可变,内容也无法修改的集合

17.15.2使用场景

​ 如果某个数据不能被修改,把它防御性地拷贝不可变集合中是个很好的实践。

​ 当集合对象被不可信的库调用时,不可变形式是安全的。

简单理解:

​ 不想让别人修改集合中的内容

17.15.3分类

  • 不可变的list集合
  • 不可变的set集合
  • 不可变的map集合

常用成员方法

image-20230425092421946

17.15.3.1不可变的list集合

public class ImmutableDemo1 {
    
    
    public static void main(String[] args) {
    
    
        /*
            创建不可变的List集合
            "张三", "李四", "王五", "赵六"
        */

        //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
        List<String> list = List.of("张三", "李四", "王五", "赵六");

        System.out.println(list.get(0));
        System.out.println(list.get(1));
        System.out.println(list.get(2));
        System.out.println(list.get(3));

        System.out.println("---------------------------");

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

        System.out.println("---------------------------");


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

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

        //list.remove("李四");
        //list.add("aaa");
        list.set(0,"aaa");
    }
}

17.15.3.2不可变的Set集合

public class ImmutableDemo2 {
    
    
    public static void main(String[] args) {
    
    
        /*
           创建不可变的Set集合
           "张三", "李四", "王五", "赵六"


           细节:
                当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性
        */

        //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
        Set<String> set = Set.of("张三", "张三", "李四", "王五", "赵六");

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

        System.out.println("-----------------------");

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

        System.out.println("-----------------------");
        //set.remove("王五");
    }
}

17.15.3.3不可变的Map集合

  • 键值对个数小于等于10
public class ImmutableDemo3 {
    
    
    public static void main(String[] args) {
    
    
       /*
        创建Map的不可变集合
            细节1:
                键是不能重复的
            细节2:
                Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对
            细节3:
                如果我们要传递多个键值对对象,数量大于10个,在Map接口中还有一个方法
        */

        //一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
        Map<String, String> map = Map.of("张三", "南京", "张三", "北京", "王五", "上海",
                "赵六", "广州", "孙七", "深圳", "周八", "杭州",
                "吴九", "宁波", "郑十", "苏州", "刘一", "无锡",
                "陈二", "嘉兴");

        Set<String> keys = map.keySet();
        for (String key : keys) {
    
    
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }

        System.out.println("--------------------------");

        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
    
    
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }
        System.out.println("--------------------------");
    }
}
  • 键值对个数大于10
public class ImmutableDemo4 {
    
    
    public static void main(String[] args) {
    
    

        /*
            创建Map的不可变集合,键值对的数量超过10个
        */

        //1.创建一个普通的Map集合
        HashMap<String, String> hm = new HashMap<>();
        hm.put("张三", "南京");
        hm.put("李四", "北京");
        hm.put("王五", "上海");
        hm.put("赵六", "北京");
        hm.put("孙七", "深圳");
        hm.put("周八", "杭州");
        hm.put("吴九", "宁波");
        hm.put("郑十", "苏州");
        hm.put("刘一", "无锡");
        hm.put("陈二", "嘉兴");
        hm.put("aaa", "111");

        //2.利用上面的数据来获取一个不可变的集合
/*
        //获取到所有的键值对对象(Entry对象)
        Set<Map.Entry<String, String>> entries = hm.entrySet();
        //把entries变成一个数组
        Map.Entry[] arr1 = new Map.Entry[0];
        //toArray方法在底层会比较集合的长度跟数组的长度两者的大小
        //如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
        //如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
        Map.Entry[] arr2 = entries.toArray(arr1);
        //不可变的map集合
        Map map = Map.ofEntries(arr2);
        map.put("bbb","222");*/


        //Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));

        Map<String, String> map = Map.copyOf(hm);
        map.put("bbb","222");
    }
}

17.16Collections集合工具类

笔记小结:

  1. 概述:java.util.Collections:是集合工具类
  2. 常用成员方法:
    1. 新增:addAll
    2. 顺序:打乱shuffle()、排序sort()、指定排序sort()、交换swap()
    3. 拷贝:copy()
    4. 填充:fill()
    5. 最大最小:max/min()
    6. 查询:binarySearch()

17.16.1概述

java.util.Collections:是集合工具类

作用:Collections不是集合,而是集合的工具类

17.16.2常用成员方法

image-20230425091419212

17.16.3基本用例

案例1

public class CollectionsDemo1 {
    
    
    public static void main(String[] args) {
    
    

        //addAll  批量添加元素
        //1.创建集合对象
        ArrayList<String> list = new ArrayList<>();
        //2.批量添加元素
        Collections.addAll(list,"abc","bcd","qwer","df","asdf","zxcv","1234","qwer");
        //3.打印集合
        System.out.println(list);

        //shuffle 打乱
        Collections.shuffle(list);

        System.out.println(list);

    }
}

案例2

public class CollectionsDemo2 {
    
    
    public static void main(String[] args) {
    
    
      /*
        public static <T> void sort(List<T> list)                       排序
        public static <T> void sort(List<T> list, Comparator<T> c)      根据指定的规则进行排序
        public static <T> int binarySearch (List<T> list,  T key)       以二分查找法查找元素
        public static <T> void copy(List<T> dest, List<T> src)          拷贝集合中的元素
        public static <T> int fill (List<T> list,  T obj)               使用指定的元素填充集合
        public static <T> void max/min(Collection<T> coll)              根据默认的自然排序获取最大/小值
        public static <T> void swap(List<?> list, int i, int j)         交换集合中指定位置的元素
     */


        System.out.println("-------------sort默认规则--------------------------");
        //默认规则,需要重写Comparable接口compareTo方法。Integer已经实现,按照从小打大的顺序排列
        //如果是自定义对象,需要自己指定规则
        ArrayList<Integer> list1 = new ArrayList<>();
        Collections.addAll(list1, 10, 1, 2, 4, 8, 5, 9, 6, 7, 3);
        Collections.sort(list1);
        System.out.println(list1);


        System.out.println("-------------sort自己指定规则规则--------------------------");
        Collections.sort(list1, new Comparator<Integer>() {
    
    
            @Override
            public int compare(Integer o1, Integer o2) {
    
    
                return o2 - o1;
            }
        });
        System.out.println(list1);

        Collections.sort(list1, (o1, o2) -> o2 - o1);
        System.out.println(list1);

        System.out.println("-------------binarySearch--------------------------");
        //需要元素有序
        ArrayList<Integer> list2 = new ArrayList<>();
        Collections.addAll(list2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println(Collections.binarySearch(list2, 9));
        System.out.println(Collections.binarySearch(list2, 1));
        System.out.println(Collections.binarySearch(list2, 20));

        System.out.println("-------------copy--------------------------");
        //把list3中的元素拷贝到list4中
        //会覆盖原来的元素
        //注意点:如果list3的长度 > list4的长度,方法会报错
        ArrayList<Integer> list3 = new ArrayList<>();
        ArrayList<Integer> list4 = new ArrayList<>();
        Collections.addAll(list3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Collections.addAll(list4, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
        Collections.copy(list4, list3);
        System.out.println(list3);
        System.out.println(list4);

        System.out.println("-------------fill--------------------------");
        //把集合中现有的所有数据,都修改为指定数据
        ArrayList<Integer> list5 = new ArrayList<>();
        Collections.addAll(list5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Collections.fill(list5, 100);
        System.out.println(list5);

        System.out.println("-------------max/min--------------------------");
        //求最大值或者最小值
        ArrayList<Integer> list6 = new ArrayList<>();
        Collections.addAll(list6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        System.out.println(Collections.max(list6));
        System.out.println(Collections.min(list6));

        System.out.println("-------------max/min指定规则--------------------------");
        // String中默认是按照字母的abcdefg顺序进行排列的
        // 现在我要求最长的字符串
        // 默认的规则无法满足,可以自己指定规则
        // 求指定规则的最大值或者最小值
        ArrayList<String> list7 = new ArrayList<>();
        Collections.addAll(list7, "a","aa","aaa","aaaa");
        System.out.println(Collections.max(list7, new Comparator<String>() {
    
    
            @Override
            public int compare(String o1, String o2) {
    
    
                return o1.length() - o2.length();
            }
        }));

        System.out.println("-------------swap--------------------------");
        ArrayList<Integer> list8 = new ArrayList<>();
        Collections.addAll(list8, 1, 2, 3);
        Collections.swap(list8,0,2);
        System.out.println(list8);



    }
}

18.泛型

笔记小结:

  1. 概述:泛型是Java中的一种特性,它可以将类或方法中的数据类型作为参数进行传递和使用

  2. 格式

    <E> <T>
    
  3. 好处:

    • 把运行时期的问题提前到了编译期间
    • 避免了强制类型转换
  4. 注意:在java中在编译为class文件时,是会擦除掉泛型的

  5. 细节:

    • 泛型中不能写基本数据类型
    • 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
    • 如果不写泛型,类型默认是Object
  6. 分类:

    1. 泛型类

      • 概念:在类名后面定义泛型,创建该类对象的时候,确定类型

      • 格式:

        修饰符 class 类名<类型>{
                   
                   
        }
        // 例如
        public class Arraylist<T>{
                   
                   
        }
        
    2. 泛型方法

      • 概念:在修饰符后面定义方法,调用该方法的时候,确定类型

      • 格式:

        修饰符<类型> 返回值类型方法名(类型变量名){
                   
                   
        }
        // 例如
        public<T> void show (T t){
                   
                   
        }
        
    3. 泛型接口

      • 概念:在接口名后面定义泛型,实现类确定类型,实现类延续泛型

      • 格式:

        修饰符 interface 接口名<类型>{
                   
                   
        }
        // 例如
        public interface List<E>{
                   
                   
        }
        
  7. 泛型通配符

    • 泛型不具备继承性,但是数据具备继承性

      public static void method( ArrayList<Animal> list) {
               
               
      }
      // 此处method方法所传入的任何参数,只能是Animal类的集合,其余任何类的集合都不行,包括子类继承的类集合也不行
      
      ArrayList<Ye> list1 = new ArrayList<>();
      list1.add(new Ye());
      list1.add(new Fu());
      list1.add(new zi());
      // 与泛型类形成对比,数据具备继承性
      
    • 泛型的通配符:?

      // 格式
      ? extend E // 传递子类
      ? super E //传递父类
      // 例如
      public static void keepPet(ArrayList<? extends Animal> list){
               
               
      }
      public static void keepPet(ArrayList<? super Animal> list){
               
               
      }
      
  8. 应用场景:

    • 定义类、方法、接口的时候,如果类型不确定,就可以定义泛型
    • 如果类型不确定,但是能知道是哪个继承体系中的,可以使用泛型的通配符

18.1概述

​ Java泛型是Java SE 5中引入的一种编程机制,它通过参数化类型来实现代码的重用。使用泛型可以让代码更加通用和类型安全,避免了在编译时期因类型转换错误导致的运行时异常。

格式:

  • <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如:
  • <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>

好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换

image-20230420203633208

说明:

在java中在编译为class文件时,是会擦除掉泛型的

细节:

  • 泛型中不能写基本数据类型
  • 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
  • 如果不写泛型,类型默认是Object

说明:

因为泛型的基本数据类型是Object类型,基本数据类型无法自动转换为Object类型

18.2分类

18.2.1泛型类

概念:泛型类(Generic Class)指在类的定义中使用泛型类型参数的类,可以在类中使用泛型类型参数,从而增强代码的可重用性和类型安全性。

格式:

修饰符 class 类名<类型>{
    
    
    
}
// 例如
public class Arraylist<T>{
    
    
    
}

说明:

此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成T、E、K、V等

示例:

image-20230420204756615

18.2.2泛型方法

概述:泛型方法(Generic Method)指在方法定义中使用泛型类型参数的方法,可以在方法中使用泛型类型参数,从而增强代码的可重用性和类型安全性。

格式

修饰符<类型> 返回值类型方法名(类型变量名){
    
    
}
// 例如
public<T> void show (T t){
    
    
}

说明:

此处T可以理解为变量,但是不是用来记录数据的,而是记录类型的,可以写成:.E、K、V等

image-20230420205709842

补充:

当使用 E … 作为参数时, … 表示可变参数,此时传入的参数个数也是不确定的

18.2.3泛型接口

概念:泛型接口(Generic Interface)指在接口的定义中使用泛型类型参数的接口,可以在接口中使用泛型类型参数,从而增强代码的可重用性和类型安全性。

格式:

修饰符 interface 接口名<类型>{
    
    
}
// 例如
public interface List<E>{
    
    
}

使用:

  • 实现类给出具体类型

image-20230420210317464

  • 实现类延续泛型,创建对象时再确定

image-20230420210249881

18.3通配符

​ 概念:泛型的通配符指的是 Java 中的通配符类型(Wildcard Type),使用 ? 表示。通配符类型是一种类型实参,可以用于表示某个泛型类型的类型参数可以是任何类型。通配符类型可以用于方法参数类型、变量类型、返回值类型等。

通配符:?也表示不确定的类型

分类:

  • ? extends E: 表示可以传递E或者E所有的子类类型
  • ? super E:表示可以传递E或者E所有的父类类型

特点:

  • 泛型的继承和通配符
  • 泛型不具备继承性,但是数据具备继承性

应用场景:

  • 如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
  • 如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符

意义:限定类型的范围

代码:

public class Test1 {
    
    
    public static void main(String[] args) {
    
    
        /*
            需求:
                定义一个继承结构:
                                    动物
                         |                           |
                         猫                          狗
                      |      |                    |      |
                   波斯猫   狸花猫                泰迪   哈士奇


                 属性:名字,年龄
                 行为:吃东西
                       波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干
                       狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼
                       泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭
                       哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家

            测试类中定义一个方法用于饲养动物
                public static void keepPet(ArrayList<???> list){
                    //遍历集合,调用动物的eat方法
                }
            要求1:该方法能养所有品种的猫,但是不能养狗
            要求2:该方法能养所有品种的狗,但是不能养猫
            要求3:该方法能养所有的动物,但是不能传递其他类型
         */


        ArrayList<PersianCat> list1 = new ArrayList<>();
        ArrayList<LiHuaCat> list2 = new ArrayList<>();
        ArrayList<TeddyDog> list3 = new ArrayList<>();
        ArrayList<HuskyDog> list4 = new ArrayList<>();

        keepPet(list1);
        keepPet(list2);
        keepPet(list3);
        keepPet(list4);
    }

    //该方法能养所有的动物,但是不能传递其他类型
    public static void keepPet(ArrayList<? extends Animal> list){
    
    
        //遍历集合,调用动物的eat方法
    }



  /*  //  要求2:该方法能养所有品种的狗,但是不能养猫
    public static void keepPet(ArrayList<? extends Dog> list){
        //遍历集合,调用动物的eat方法
    }*/


    /*//要求1:该方法能养所有品种的猫,但是不能养狗
    public static void keepPet(ArrayList<? extends Cat> list){
        //遍历集合,调用动物的eat方法
    }*/
}

知识加油站

1.数据结构

笔记小结:

  1. 概述:数据结构是计算机存储、组织数据的方式
  2. 栈:后进先出,先进后出。
  3. 队列:先进先出,后进后出。
  4. 数组:内存连续区域,查询快,增删慢。
  5. 链表:元素是游离的,查询慢,首尾操作极快。
  6. 树:请查看各个小节

1.1概述

​ 数据结构是计算机存储、组织数据的方式,是指数据元素之间的相互关系,以及它们之间在计算机存储器中的组织方式。常见的数据结构包括数组、链表、栈、队列、树、图等,它们在实际的计算机程序设计中扮演着重要的角色

image-20230328210954016

1.2栈

栈特点:先进后出,后进先出

image-20230420170514263

java中方法

image-20230420170558867

说明:

方法存在栈内存中,当function<-method<-main方法入栈后,会以function->methon->main的方式出栈

1.3队列

队列特点:先进先出,后进后出

image-20230420170844956

说明:

类似于生活中的排队买票

1.4数组

特点:数组是一种查询快,增删慢的模型

image-20230420171022878

  • **查询速度快:**查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
  • 删除效率低:要将原始数据删除,同时后面每个数据前移。
  • 添加效率极低:添加位置后的每个数据后移,再添加元素。

1.5链表

特点:链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址

image-20230420171528194

  • 链表查询慢,无论查询哪个数据都要从头开始找。
  • 链表增删相对快

image-20230420171502885

1.6树

笔记小节:

  1. 概述:

    • 节点: 在树结构中,每一个元素称之为节点

      image-20230421092414995

    • 度: 每一个节点的子节点数量称之为度

  2. 二叉树:

    ​ 每个节点最多两个子节点,分别称为左子节点和右子节点。左子节点的值小于或等于父节点的,右子节点的值大于父节点的,这种性质使得二叉树在查找、排序等方面有很好的应用。二叉树的子树也是二叉树,即每个节点都可以看作是根节点

    image-20230811230654303

  3. 二叉查找数:

    ​ 每个节点包含一个键值对(key-value)、左子树的所有节点的键值小于根节点的键值、右子树的所有节点的键值大于根节点的键值左子树右子树也是二叉查找树。

    image-20230811230406817

  4. 平衡二叉树:

    ​ 叉树左右两个子树的高度差不超过1、任意节点的左右两个子树都是一颗平衡二叉树image-20230423083649743

  5. 红黑数:

    1. 特点:平衡二叉B树、每一个节点可以是红或者黑、红黑树不是高度平衡的,它的平衡是通过"自己的红黑规则"进行实现的

    2. 红黑规则:

      ​ 每一个节点或是红色的,或者是黑色的。根节点必须是黑色。如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的。如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)。对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

    image-20230811225057199

  6. 树的演变image-20230421092905390

1.6.1二叉树

特点:二叉树中,任意一个节点的度要小于等于2

  • 节点: 在树结构中,每一个元素称之为节点

    image-20230811231622595

  • 度: 每一个节点的子节点数量称之为度

image-20230811224958660

1.6.2二叉查找树

特点:

  • 每一个节点上最多有两个子节点
  • 任意节点左子树上的值都小于当前节点
  • 任意节点右子树上的值都大于当前节点

image-20230811230851159

1.6.3平衡二叉树

image-20230423083627548

特点:

  • 二叉树左右两个子树的高度差不超过1
  • 任意节点的左右两个子树都是一颗平衡二叉树

旋转:

  1. 旋转触发时机

    • 当添加一个节点之后,该树不再是一颗平衡二叉树
  2. 左旋:

    • 就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
      • image-20230811230957523
      • image-20230811231031684
  3. 右旋:

    • 就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点
      • image-20230811231105098
      • image-20230811231113475
  4. 平衡二叉树旋转的四种情况:

    1. 左左:当根节点左子树的左子树有节点插入,导致二叉树不平衡

      • 如何旋转: 直接对整体进行右旋即可

        image-20230811231246299

    2. 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡

      • 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋

        image-20230811231255872

    3. 右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡

      • 如何旋转: 直接对整体进行左旋即可
    • image-20230811231402589
  5. 右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡

    • 如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋

      image-20230811225021706

参考资料:集合进阶-11数据结构(平衡二叉树旋转机制)_哔哩哔哩_bilibili

1.6.4红黑树

特点:

  • 平衡二叉B树
  • 每一个节点可以是红或者黑
  • 红黑树不是高度平衡的,它的平衡是通过"自己的红黑规则"进行实现的

红黑规则:

  1. 每一个节点或是红色的,或者是黑色的

  2. 根节点必须是黑色

  3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的

  4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)

  5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

image-20230811225047728

  • 红黑树添加节点的默认颜色:添加节点时,默认为红色,效率高

    image-20230811231504780

  • 红黑树添加节点后如何保持红黑规则

    image-20230421103132809

2.可变参数

笔记小结:

  1. 概述:可变参数是一种Java方法的参数类型,允许方法接受任意数量的参数

  2. 特点:可变参数本质上就是一个数组

  3. 作用:在形参中接收多个数据

  4. 格式:数据类型…参数名称

    getSum(1,2,3,4,5,6,7,8,9,10);
    
    public static int getSum( int a,int...args) {
           
           
        return 0;
    }
    
  5. 注意:

    • 形参列表中可变参数只能有一个可变参数
    • 形参列表中可变参数必须放在形参列表的最后面

2.1定义

​ 可变参数是一种Java方法的参数类型,允许方法接受任意数量的参数。在方法声明中,可变参数使用省略号(…)来表示,它可以接收0个或多个相同类型的参数。使用可变参数的方法可以接受任意数量的参数,而无需提前声明它们的数量。在方法中,可变参数实际上是作为数组来处理的

2.2特点

  • 可变参数本质上就是一个数组

2.3作用

  • 在形参中接收多个数据

格式

  • 数据类型…参数名称

基本用例:

public class ArgsDemo4 {
    
    
    public static void main(String[] args) {
    
    
        //可变参数的小细节:
        //1.在方法的形参中最多只能写一个可变参数
        //可变参数,理解为一个大胖子,有多少吃多少
        //2.在方法的形参当中,如果出了可变参数以外,还有其他的形参,那么可变参数要写在最后
        getSum(1,2,3,4,5,6,7,8,9,10);
    }

    public static int getSum( int a,int...args) {
    
    
        return 0;
    }
}

3.Lambda表达式

3.1概述

​ Lambda表达式是Java编程语言中引入的一种语法特性,用于创建匿名函数或闭包。它允许您以更简洁的方式定义单个方法的接口实现。Lambda表达式在函数式编程和简化代码编写方面具有重要作用,特别是在集合处理和多线程编程中。

补充:

​ 此处的单个方法的接口实现,简称函数式接口。该接口有且仅有一个抽象方法。有且仅有一个抽象方法的接口叫做函数式接口,接口上方可以加**@Functionallnterface**注解。

image-20230321135748558

说明:

​ 在本方法中,简化new出来的接口为箭头函数

3.2作用

​ 把Lambda表达式理解为是一段可以传递的代码,它可以写出更简洁更灵活的代码,作为一种更紧凑的代码风格,使Java语言表达能力得到了提升。换句话说,简化函数式接口的匿名内部类的写法

3.3语法

省略核心:可推导,可省略

  • 参数类型可以省略不写。
  • 如果只有一个参数,参数类型可以省略,同时**()也可以省略**。
  • 如果Lambda表达式的方法体只有一行大括号,分号,return可以省略不写,需要同时省略。

3.4函数式编程

​ 函数式编程(Functional programming)是一种思想特点。面向对象∶先找对象,让对象做事情。

​ 函数式编程思想,忽略面向对象的复杂语法,强调做什么,而不是谁去做。

格式:

() ->{
    
     //( )对应着方法的形参 ->固定格式
    
} //{ } 对应着方法的方法体

说明:

  • Lambda表达式可以用来简化匿名内部类的书写
  • Lambda表达式只能简化函数式接口的匿名内部类的写法

4.函数式接口

​ 函数式接口是指只包含一个抽象方法的接口。在Java中,可以使用@FunctionalInterface注解来标记一个接口是函数式接口,这样做可以帮助编译器检查接口是否符合函数式接口的定义。

​ 函数式接口在Java 8中引入了Lambda表达式和方法引用等新特性。Lambda表达式可以将函数式接口作为参数进行传递,从而简化代码实现。Java标准库中的一些函数式接口包括ConsumerSupplierPredicateFunction等等,这些接口可以用于在Java中实现函数式编程的思想。

​ 函数式接口,也就意味着,可以使用Lambad表达式或者匿名内部类进行传递,从而简化代码实现。

5.迭代器源码分析

image-20230420201035922

说明:

  • list.iterator(),每调用一次就会创建一个新的迭代器

  • hasNext(),判断当前指针位置是否和迭代对象的长度相同

  • next(),先判断是否使用了集合中的添加或者删除方法,然后返回当前索引的元素,然后将指针移动到下一个位置

6.Equals()方法和==`运算符区别

equals()方法是用于比较两个对象的值是否相等,通常在自定义类中重写equals()方法来实现自定义的相等比较规则。默认情况下,equals()方法实际上等同于==运算符,即比较两个对象的引用是否相等。

==运算符用于比较两个对象的引用是否指向同一内存地址。如果两个对象的引用指向同一个内存地址,那么它们是相等的,否则它们不相等。

String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");

System.out.println(str1 == str2); // true,因为它们指向同一字符串常量池中的对象
System.out.println(str1 == str3); // false,因为它们指向不同的内存地址
System.out.println(str1.equals(str3)); // true,因为它们的值相等

​ 需要注意的是,对于基本数据类型,==运算符可以用于比较它们的值是否相等,因为基本数据类型在内存中存储的是它们的值而不是引用。但对于对象类型,==运算符比较的是对象的引用,而不是值。因此,在比较对象相等性时,应该使用equals()方法而不是==运算符。

猜你喜欢

转载自blog.csdn.net/D_boj/article/details/132241235