05-集合

集合

集合的体系图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-68bQgx1U-1669232941562)(F:\BigData\java\图片\day09图片\集合体系图.png)]

简介:

概述

集合是用来存储多个同类型元素的容器, 它的长度是 可变的

体系

  • 单列集合:顶层接口是:Collection

  • List体系

    • 特点:有序(元素的存 取 顺序一致),可重复元素有索引

    • 常用子类:

      • ArrayList:底层数据结构采用的是数组,所以查询(修改)相对较快,增删相对较慢,线程不安全,效率相对较高。

      • LinkedList:底层数据结构采用的是链表,所以查询(修改)相对较慢,增删相对较块,线程不安全,效率相对较高。

  • Set体系

    • 特点:无序(元素的存 取 顺序不一致),唯一,元素无索引(解释:其实底层是有索引的,但是我们不能用,所以我们理解为无索引)。
      • 常用子类:
        • HashSet:底层数据结构采用的是哈希表(数组 + 链表),增删改查都快,线程不安全,效率相对较高。
        • TreeSet:底层数据结构采用二叉树,可以对元素进行排序,但是这个我们不讲,因为实际开发中的数据从SQL中提取出来的时候就是排好序的。
  • 双列集合:顶层接口是:Map

    • 特点:存储的是键值对元素,其中键具有唯一性值可以重复,数据结构只针对于键有效。
    • 常用子类:
      • HashMap:底层数据结构采用是哈希表(数组 + 链表),增删改查都快,线程不安全,效率相对较高。
      • TreeMap:底层数据结构采用二叉树,可以对键进行排序,但是这个我们不讲,因为实际开发中的数据从SQL中提取出来的时候就是排好序的。
  • 小技巧:

    1. 集合的顶层都是接口(例如:Collection,List,Set,Map),IO流的顶层都是抽象类(InputStream,OutputStream,Reader,Writer)
    2. 以后但凡我们学习一个新的继承体系,建议采用:学顶层,用底层的方式,因为顶层定义的是整个继承体系的 共性内容,而底层才是具体的体现,实现

Collection集合

泛型
  • 概述:

    • 泛型的意思是: 泛指某种具体的数据类型.
  • 写法:
    <数据类型>

  • 作用:
    泛型一般只和集合相结合使用, 用来限定集合中元素的数据类型的.

  • 分类: //了解, 前期用不到.

    • 泛型类: 把泛型定义到类上, 就叫泛型类
    • 泛型方法: 把泛型定义到方法上, 就叫泛型方法
    • 泛型接口: 把泛型定义到接口上, 就叫泛型接口
  • 注意事项:
    1. 泛型必须是 引用类型.
    2. 前后泛型必须保持一致, 或者后边的泛型可以省略不写(JDK1.7的新特性: 菱形泛型)
    3. 泛型在实际开发中, 一般只和集合相结合使用, 用来限定集合中元素的数据类型的.
    4. 泛型一般用字母E, T, K, V表示.
    E: Element(元素), T: Type(类型), K: Key(键), V: Value(值)

入门案例

package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Collection;

public class Demo04 {
    public static void main(String[] args) {
        //1.创建集合
        //Collection list = new ArrayList();  //不采用泛型,可以添加任意类型的数据
        
        //采用泛型,因为泛型是String,所以该集合只能添加字符串
		Collection<String> list = new ArrayList<String>();

        //2.添加元素到集合中
        list.add("hello");
        list.add("world");
        list.add("java");

        System.out.println(list);
        //ArrayList类已经重写了Object#toString()方法
    }
}

成员方法
  • public boolean add(E e) 添加元素,
    • 如果是List体系,返回值都是true,
    • 如果是Set体系:重复不添加是false,不重复就添加是true.
  • public boolean remove(Object obj) 从集合中移除指定的元素.
  • public void clear() 清空集合对象.
  • public boolean contains(Object obj) 判断集合中是否包含指定的元素.
  • public boolean isEmpty() 判断集合是否为空.
  • public int size() 获取集合的长度, 即集合中元素的个数.

案例:测试Collection集合中的成员方法

package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Collection;

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

        //2.添加元素
        //测试:public boolean add(E e)             添加元素, 如果是List体系, 返回值都是true,如果是Set体系:重复不添加是false, 不重复就添加是true.
        System.out.println(list.add("hello"));
        System.out.println(list.add("java"));
        System.out.println(list.add("world"));

        //测试:public boolean remove(Object obj)   从集合中移除指定的元素.
        System.out.println(list.remove("java"));
        //测试:public void clear()                清空集合对象.
        list.clear();
        //测试:public boolean contains(Object obj) 判断集合中是否包含指定的元素.
        System.out.println(list.contains("hello"));
        //测试:public boolean isEmpty()            判断集合是否为空.
        System.out.println(list.isEmpty());
        //测试:public int size()                   获取集合的长度, 即集合中元素的个数.
        System.out.println(list.size());

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

集合的核心操作步骤:
  1. 创建集合对象.
  2. 创建元素对象.
  3. 添加元素到集合中
  4. 遍历集合.
    4.1 根据集合对象获取其对应的迭代器对象. Collection#iterator()
    即: 根据仓库获取管理该仓库的 仓库管理员.
    4.2 (迭代器)判断是否有下一个元素. Iterator#hasNext()
    4.3 如果有, 就获取. Iterator#next()

方法解释

  • public Iterator iterator(); 根据集合对象获取其对应的迭代器对象
    Iterator接口中的成员方法:
  • public boolean hasNext(); 判断迭代器中是否有下一个元素.
    public E next(); 如果有, 就获取下一个元素.
Collection集合存储字符串,并遍历
package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo06 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        Collection<String> list = new ArrayList<>();
        //2. 创建元素对象.
        //String s1 = "hello";
        //3. 添加元素到集合中.
        //list.add(s1);
        list.add("hello");
        list.add("world");
        list.add("java");

        //4. 遍历集合.
        //4.1 根据集合对象获取其对应的迭代器对象.      Collection#iterator()
        Iterator<String> it = list.iterator();
        //4.2 (迭代器)判断是否有下一个元素.           Iterator#hasNext()
        while (it.hasNext()){
            //4.3 如果有, 就获取.                       Iterator#next()
            String s = it.next();
            System.out.println(s);
        }
    }
}
Collection集合存储学生,并遍历

学生类

package com.ithiema.api.demo;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

测试类

package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo07 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        Collection<Student> coll = new ArrayList<>();
        //2. 创建元素对象.
        Student s1 = new Student("张三", 33);
        Student s2 = new Student("李四", 34);
        Student s3 = new Student("王五", 35);
        //3. 添加元素到集合中.
        coll.add(s1);
        coll.add(s2);
        coll.add(s3);
        //4. 遍历集合.
        //4.1 根据集合对象获取其对应的迭代器对象.      Collection#iterator()
        Iterator<Student> it = coll.iterator();
        //4.2 (迭代器)判断是否有下一个元素.           Iterator#hasNext()
        while (it.hasNext()) {
            //4.3 如果有, 就获取.                       Iterator#next()
            Student s = it.next();
			//System.out.println(s);
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

List集合

  • 概述:
    • 它表示单列集合, 也叫有序集合(简称: 序列), 属于Collection集合的子体系.
    • 它是java.util包下的接口, 用之前需要先导包.
  • 元素特点:
    • 有序:指的是元素的存取顺序一致.
    • 可重复:指的是能存储重复元素.
    • 元素有索引:指的是List集合中每个元素都是有索引的, 索引从 0 开始.
成员方法
  • public void add(int index, E element) 在集合的指定位置(索引), 插入指定的元素
  • public E remove(int index) 删除指定索引处的元素, 并返回被删除的元素
  • public E set(int index, E element) 修改指定索引处的元素为指定的值, 并返回修改前的元素
  • public E get(int index) 根据索引, 获取其对应的元素
    • 上述4个方法的共同点是: 索引不存在会报 IndexOutOfBoundsException(索引越界异常)

案例

package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Demo08 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        List<String> list = new ArrayList<>();
        //2. 创建元素对象
        //3. 添加元素到集合中.
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("world");
        //4. 遍历集合.
        //4.1 根据集合对象获取其对应的迭代器对象.      Collection#iterator()
        Iterator<String> it = list.iterator();
        //4.2 (迭代器)判断是否有下一个元素.           Iterator#hasNext()
        while (it.hasNext()) {
            //4.3 如果有, 就获取.                       Iterator#next()
            String s = it.next();
            System.out.println(s);
        }
    }
}
案例:演示List集合存储自定义类型的对象并遍历
package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Demo08 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        List<String> list = new ArrayList<>();
        //2. 创建元素对象
        //3. 添加元素到集合中.
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("world");
        //4. 遍历集合.
        //4.1 根据集合对象获取其对应的迭代器对象.      Collection#iterator()
        Iterator<String> it = list.iterator();
        //4.2 (迭代器)判断是否有下一个元素.           Iterator#hasNext()
        while (it.hasNext()) {
            //4.3 如果有, 就获取.                       Iterator#next()
            String s = it.next();
            System.out.println(s);
        }

        //方式2:普通for循环遍历
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
    }
}
案例:List集合存储学生对象,并遍历
  • 遍历方式:
    • 普通迭代器
    • 普通for循环

学生类

package com.ithiema.api.demo;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

测试类:遍历学生集合

package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Demo09 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        List<Student> list = new ArrayList<>();
        //2. 创建元素对象.
        Student s1 = new Student("张三", 33);
        Student s2 = new Student("李四", 34);
        Student s3 = new Student("王五", 35);
        //3. 添加元素到集合中.
        list.add(s1);
        list.add(s2);
        list.add(s3);
        //4. 遍历集合.
        //4.1 根据集合对象获取其对应的迭代器对象.      Collection#iterator()
        Iterator<Student> it = list.iterator();
        //4.2 (迭代器)判断是否有下一个元素.           Iterator#hasNext()
        //快捷键 itit
        while (it.hasNext()) {                  
            //4.3 如果有, 就获取.                       Iterator#next()
            Student s = it.next();
            System.out.println(s);
        }

        //方式2:普通for循环       快捷键 itli -> iterator list
        for (int i = 0; i < list.size(); i++) {
            Student s = list.get(i);
            System.out.println(s);
        }
    }
}

列表迭代器

简介
  • 概述:

    • 它指的是ListIterator接口, 也是Iterator接口的子接口, 表示列表迭代器, 它是独属于List体系的迭代器
  • 涉及到的成员方法:

    • List集合中的成员方法:
      • public ListIterator listIterator(); 根据List集合, 获取其对应的列表迭代器.
    • ListIterator中的成员方法:
      • public boolean hasNext(); 判断迭代器中是否有下一个元素, 该方法是从 Iterator接口继承过来的
      • public E next(); 有就获取下一个元素, 该方法是从 Iterator接口继承过来的
      • public boolean hasPrevious(); 判断迭代器中是否有上一个元素, 该方法是ListIterator独有的
      • public E previous(); 有就获取上一个元素, 该方法是 ListIterator独有的
  • 细节:

    • 进行逆向遍历之 前必须先进行一次正向遍历, 且正向和逆向遍历必须使用同一个列表迭代器对象
    • 列表迭代器一般用于解决 并发修改异常(ConcurrentModificationException)
案例:列表迭代器详解,正向遍历和逆向遍历
package com.ithiema.api.demo;

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

public class Demo10 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        List<String> list = new ArrayList<>();
        //2. 创建元素对象.
        //3. 添加元素到集合中.
        list.add("hello");
        list.add("world");
        list.add("java");
        //4. 遍历集合.
        //4.1 列表迭代器 正向遍历
        ListIterator<String> lit = list.listIterator();
        while (lit.hasNext()) {
            String s = lit.next();
            System.out.println(s);
        }

        System.out.println("------------------------");
        
        //4.2 列表迭代器 逆向遍历
        while (lit.hasPrevious()) {
            String s =  lit.previous();
            System.out.println(s);
        }
    }
}
并发修改异常
  • 概述:
    • 并发修改异常指的是ConcurrentModificationException, 一般多见于集合部分, 如果业务没有捋顺当, 就有可能出现此问题.
  • 问题描述:
    • 当用普通迭代器遍历集合的同时, 又往集合中添加元素, 此时就会报: 并发修改异常.
    • 注意: 这个仅仅是并发修改异常的产生原因之一, 其他情况也有可能会出现并发修改异常, 你不需要重点关心它是如何出现的, 而是重点关注怎么解决.
  • 产生原因:
    • 在你通过集合对象获取迭代器对象的时候, 其实普通迭代器底层会有一个变量记录住此时集合中元素的个数, 当集合中实际元素的个数比这个值要大的时候,就会报并发修改异常
  • 解决方案:
      1. 通过 列表迭代器 (listIterator)解决, 添加的元素是在当前元素之后.
      2. 通过 普通for循环 解决, 添加的元素是在集合最后.
      3. 通过 CopyOnWriteArrayList集合 解决, 添加的元素是在集合最后.
案例:并发修改异常
package com.ithiema.api.demo;

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

public class Demo11 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        List<String> list = new ArrayList<>();
        //2. 创建元素对象.
        //3. 添加元素到集合中.
        list.add("hello");
        list.add("world");
        list.add("java");

        //4.遍历集合

        //以下代码会报并发修改异常
        /*Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            //4.1 判断s是否是“world”,如果是,就添加“hadoop”
            if("world".equals(s)){
                list.add("hadoop");
            }
        }*/

        //解决方案1:通过 列表迭代器 解决,添加的元素是当前元素之后
        ListIterator<String> lit = list.listIterator();
        while (lit.hasNext()) {
            String s = lit.next();
            if ("world".equals(s)){
                //list.add("hadoop");       //还是会报并发修改异常
                lit.add("hadoop");          //细节:必须用列表迭代器 的添加元素的方法
            }
        }

        //解决方案2:通过 普通for循环 解决,添加的元素是在集合后面
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            if("world".equals(s)){
                list.add("hadoop");
            }
        }

        //5.打印集合
        System.out.println(list);
    }
}

解决方案3:通过 CopyOnWriteArrayList集合 解决

package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class Demo12 {
    public static void main(String[] args) {
        //1. 创建集合对象.
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        //2. 创建元素对象.
        //3. 添加元素到集合中.
        list.add("hello");
        list.add("world");
        list.add("java");

        //4.遍历集合

        //以下代码会报并发修改异常
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            //4.1 判断s是否是“world”,如果是,就添加“hadoop”
            if("world".equals(s)){
                list.add("hadoop");
            }
        }

        //5.打印集合
        System.out.println(list);
    }
}

增强for

  • 概述

  • 它是JDK1.5的新特性, 用来简化遍历数组和集合操作的

  • 格式

    • for(数据类型 变量名: 要遍历的集合或者数组) {
      		//变量名其实就代表数组或者集合中的每一个元素.
      }
      
  • 注意事项:

    1. 增强for 的本质就是一个 普通迭代器.
    2. 你用增强for 遍历集合的同时往集合中加元素了, 也会报并发修改异常
  • 快捷键:iter

案例:增强for 遍历数组列表

package com.ithiema.api.demo;

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

public class Demo14 {
    public static void main(String[] args) {
        
        int[] arr = {11, 22, 33, 44, 55};
        for (int i : arr) {
            System.out.println(i);
        }

        System.out.println("---------------------");
        
        List<String> list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

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

常见的数据结构

特点:
  • :先进后出,后进先出。 作用:1.存储所用的局部变量2.所用代码执行。
  • 队列:先进先出,后进后出。 存数据动作叫 入队,取数据动作叫 出队。
  • 数组:查询(修改)快,增删慢。
  • 链表:查询(修改)慢,增删快。
    • 节点:由数值域 和地址域组成
    • 链表:由节点组成的一条链子。
      • 根据节点不同,链表主要分为:
        1. 单向链表
        2. 单向循环列表
        3. 双向链表
        4. 双向循环链
栈和队列图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mrl4yeko-1669232941564)(F:\BigData\java\图片\day10图片\01栈和队列.png)]

数组和链表图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IilQEVaG-1669232941564)(F:\BigData\java\图片\day10图片\02数组和链表.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GdyCSCoe-1669232941565)(F:\BigData\java\图片\day10图片\链表.png)]

List集合的子类

常用的子类

List集合是一个接口, 它的常用子类有两个, 分别是ArrayList, LinkedList.

  • ArrayList集合的特点:底层数据结构是数组, 查询和修改快, 增删慢.
  • LinkedList集合的特点:底层数据结构是链表, 查询和修改慢, 增删快.

注意: 它们的相同点是, 都是有序的, 而且可以存储重复元素.

ArrayList集合
案例1_ArrayList集合存储字符串并遍历
package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.ListIterator;

public class Demo15 {
    public static void main(String[] args) {
        //1.创建集合对象
        ArrayList<String> list = new ArrayList<>();
        //2. 创建元素对象.
        //3. 添加元素到集合中.
        list.add("hello");
        list.add("world");
        list.add("java");

        //4. 遍历集合.
        //方式1:增强for     iter
        for (String s : list) {
            System.out.println(s);
        }

        System.out.println("----------------------------");
        //方式2:普通for循环       itli
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }

        System.out.println("----------------------------");
        //方式3:列表迭代器     itit
        ListIterator<String> lit = list.listIterator();
        while (lit.hasNext()) {
            String s = lit.next();
            System.out.println(s);
        }

        System.out.println("----------------------------");
        //方式4:普通迭代器     itit
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }

        System.out.println("----------------------------");
        //方式5:转数组遍历,凑数的,实际开发不用
        Object[] obj = list.toArray();
        for (Object o : obj) {
            System.out.println(o);
        }
    }
}
案例2_ArrayList集合存储学生并遍历

学生类

package com.ithiema.api.demo;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

测试类,遍历集合

package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

public class Demo16 {
    public static void main(String[] args) {
        //1.创建集合对象
        ArrayList<Student> list = new ArrayList<>();

        //2. 创建元素对象.
        Student s1 = new Student("张三", 23);
        Student s2 = new Student("李四", 24);
        Student s3 = new Student("王五", 25);
        //3. 添加元素到集合中.
        list.add(s1);
        list.add(s2);
        list.add(s3);
        //4. 遍历集合.
        //方式1:增强for     iter
        for (Student s : list) {
            System.out.println(s);
        }
        System.out.println("----------------------------");
        //方式2:普通for循环    itli
        for (int i = 0; i < list.size(); i++) {
            Student s = list.get(i);
            System.out.println(s);
        }

        System.out.println("----------------------------");
        //方式3:列表迭代器     itit
        ListIterator<Student> lit = list.listIterator();
        while (lit.hasNext()) {
            Student s = lit.next();
            System.out.println(s);
        }

        System.out.println("----------------------------");
        //方式4:普通迭代器     itit
        Iterator<Student> it = list.iterator();
        while (it.hasNext()) {
            Student s = it.next();
            System.out.println(s);
        }

        System.out.println("----------------------------");
        //方式5:转数组遍历,凑数的,实际开发不用
        Object[] objects = list.toArray();
        for (Object object : objects) {
            System.out.println(object);
        }
    }
}
LinkedList集合
  • 概述
    • 它属于List体系, 元素特点是: 有序, 可重复, 元素有索引.
    • 它的底层数据结构采用的
    • 链表, 所以查询修改相对较慢, 增删相对较快.
成员方法
  • public void addFirst(E e) 往列表的开头插入指定的元素
  • public void addLast(E e) 往列表的末尾插入指定的元素
  • public E removeFirst() 删除列表中的第一个元素, 并返回被删除的元素
  • public E removeLast() 删除列表中的最后一个元素, 并返回被删除的元素.
  • public E getFirst() 返回列表的第一个元素
  • public E getLast() 返回列表的最后一个元素
案例一: LinkedList入门
package com.itheima.demo06_linkedlist;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

//案例: 演示LinkedList集合入门.
//概述: LinkedList集合解释: 底层数据结构是链表, 所以增删快, 查询修改慢.
public class Demo01 {
    public static void main(String[] args) {
        //1.创建LinkedList集合对象, 存储字符串数据: "hello", "world", "java"
        LinkedList<String> list =  new LinkedList<>();
        list.add("hello");
        list.add("world");
        list.add("java");

        //2.遍历LinkedList集合.
        //方式一: 普通的迭代器.
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("--------------------------------");

        //方式二: 普通for
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
        System.out.println("--------------------------------");

        //方式三: 增强for
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("--------------------------------");

        //方式四: 列表迭代器
        ListIterator<String> lit = list.listIterator();
        while (lit.hasNext()) {
            String s = lit.next();
            System.out.println(s);
        }
        System.out.println("--------------------------------");

        //方式五: 转数组遍历
        Object[] objs = list.toArray();
        for (Object obj : objs) {
            System.out.println(obj);
        }

    }
}
案例二:LinkedList的特有方法
package com.itheima.demo06_linkedlist;

import java.util.LinkedList;

//案例: 演示LinkedList集合独有的方法.
public class Demo02 {
    public static void main(String[] args) {
        //1.创建LinkedList集合对象, 存储字符串数据: "hello", "world", "java"
        LinkedList<String> list = new LinkedList<>();
        list.add("hello");
        list.add("world");
        list.add("java");
        //2.分别演示上述的6个方法.
        //演示添加.
        /*list.addFirst("黑马程序员");
        //list.addLast("传智播客");
        list.add("传智播客");*/

        //演示删除元素
        //System.out.println(list.removeFirst());
        //System.out.println(list.removeLast());

        //演示获取
        System.out.println(list.getFirst());
        System.out.println(list.getLast());

        //3, 打印集合
        System.out.println("list: " + list);
    }
}

Set集合

  • 概述:

    • 它属于单列集合, 是Collection集合的子体系.
  • 元素特点:

    • 无序(元素的存取顺序不一致), 唯一, 元素无索引.
  • 常用子类:

    • HashSet:底层数据结构采用哈希表, 增删改查都快, 线程不安全, 效率高.
案例: 演示Set集合入门
package com.itheima.demo01_set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

//案例: 演示Set集合入门
//记忆: Set集合是Collection的子接口, 它的元素特点是: 无序, 唯一.
//Set集合其实底层也是有索引的, 只是不对外暴漏, 作为程序员我们无法直接使用Set集合的索引.
public class Demo01 {
    public static void main(String[] args) {
        //1.创建Set集合对象, 存储字符串数据: "hello", "world", "java", "world"
        Set<String> hs = new HashSet<>();
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");

        //2.通过两种方式, 遍历Set集合.
        //方式一: 普通迭代器
        Iterator<String> it = hs.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("--------------------");

        //方式二: 增强for
        for (String s : hs) {
            System.out.println(s);
        }
        System.out.println("--------------------");

        //方式三: 转数组遍历, 了解.
        Object[] objs = hs.toArray();
        for (Object obj : objs) {
            System.out.println(obj);
        }
    }
}

哈希值
  • 概述

    • 所谓的哈希值, 就是JDK根据对象的地址, 属性等各种信息算出来的一个 int 类型的值.
  • 问题: 如何获取哈希值呢?

    • 答案: 可以通过Object#hashCode()方法实现.
      public int hashCode(); 获取对象的哈希值.
  • 结论:

    1. 实际开发中, 我们认为, 如果同一个类的两个对象, 各个属性都相同, 那么它们就是同一个对象.
    2. 同一对象哈希值肯定相同, 不同对象哈希值一般不同.
      3. 同一个对象多次调用 hashCode()方法, 获取的结果也是一样的.
      4. 默认情况下, 不同对象哈希值是不同的, 但是我们可以手动重写Object#hashCode(), 实现: 不同对象的哈希值也是相同的.
      但是没有什么意义, 一般也不会这么做.
      5. 原则: 保证同一对象哈希值必须相同, 不同对象哈希值尽量不同.
      6. 实际开发做法: 快捷键生成, 重写Object#hashCode().
案例: 哈希值入门

定义JavaBean类, 表示学生类.

package com.itheima.pojo;

//定义JavaBean类, 表示学生类.
public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @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;
    }

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

测试类

package com.itheima.demo01_set;

import com.itheima.pojo.Student;

//案例: 哈希值入门.

public class Demo02 {
    public static void main(String[] args) {
        //1.定义学生类, 属性为姓名和年龄.
        //2.在测试类的main方法中, 创建两个学生对象, 分别获取它们的哈希值, 并打印.
        Student s1 = new Student("刘亦菲", 33);
        Student s2 = new Student("刘亦菲", 33);
        Student s3 = new Student("赵丽颖", 31);
		
        //3.测试: 重写Object#hashCode()方法, 实现不同对象的哈希值也是相同的.
        System.out.println("s1: " + s1.hashCode());		//s1: 646483581
        System.out.println("s2: " + s2.hashCode());		//s2: 646483581
        System.out.println("s3: " + s3.hashCode());		//s3: 1099280305

        //4.测试: 同一对象哈希值肯定相同, 不同对象哈希值一般不同.
        //重地和通话, 儿女和农丰	哈希值相同情况
        System.out.println("重地abc".hashCode());
        System.out.println("通话abc".hashCode());
        System.out.println("-------------------------");
        System.out.println("儿女".hashCode());
        System.out.println("农丰".hashCode());

    }
}
HashSet集合
  • 简介

    • 它属于Set体系, 元素特点是: 无序, 唯一, 元素无索引.
      底层数据结构采用哈希表(数组+链表), 增删改查都快, 线程不安全, 效率高.
  • 问题: HashSet集合保证元素唯一性的原理是什么?

    • 答案:HashSet集合保证元素的唯一性依赖 **hashCode()equals()**方法,
      • 即: 存储什么元素, 只要让该元素的类型重写这两个方法即可,快捷键生成
案例: 演示HashSet集合的使用
package com.itheima.demo01_set;

import java.util.HashSet;
import java.util.Iterator;

//案例: 演示HashSet集合的使用.
//记忆: HashSet集合的特点是: 无序, 唯一, 元素无索引, 它的底层数据结构是: 哈希表(数组 + 链表).
public class Demo03 {
    public static void main(String[] args) {
        //1.定义HashSet集合, 存储字符串"hello", "world", "java", "world"
        HashSet<String> hs = new HashSet<>();
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");
        hs.add(null);
        hs.add(null);
        //2.遍历HashSet集合, 打印每一个元素值, 并观察程序的运行结果.
        //方式一: 增强for
        for (String h : hs) {
            System.out.println(h);
        }
        System.out.println("-------------------");

        //方式二: 普通的迭代器
        Iterator<String> it = hs.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}
案例: 演示HashSet存储在自定义对象, 并保证唯一性

JavaBean类:学生类

package com.itheima.pojo;

//定义JavaBean类, 表示学生类.
public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @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;
    }

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

测试类:

package com.itheima.demo01_set;

import com.itheima.pojo.Student;

import java.util.HashSet;

//案例: 演示HashSet存储在自定义对象, 并保证唯一性.
//细节: 记得在自定义类中重写hashCode()和equals()方法.
public class Demo04 {
    public static void main(String[] args) {
        //1.定义学生类, 属性为姓名和年龄.
        //2.创建HashSet集合, 用来存储学生对象, 并往其中添加3个学生的信息.
        HashSet<Student> hs = new HashSet<>();
        hs.add(new Student("刘亦菲", 33));
        hs.add(new Student("赵丽颖", 31));
        hs.add(new Student("赵丽颖", 31));
        hs.add(new Student("高圆圆", 35));
        hs.add(new Student("高圆圆", 35));

        //3.遍历集合, 并把结果打印到控制台上.
        for (Student student : hs) {
            System.out.println(student);
        }
        //结果:唯一性
        //Student{name='赵丽颖', age=31}
        //Student{name='刘亦菲', age=33}
        //Student{name='高圆圆', age=35}
    }
}
LinkedHashSet集合
  • 简介
    • 它是HashSet集合的子类, 元素特点是: 有序, 唯一.
    • 它的底层数据结构采用的是 链表 + 哈希表的形式, 由链表保证有序, 哈希表保证唯一.
package com.itheima.demo01_set;

import java.util.LinkedHashSet;

//案例: 演示LinkedHashSet集合.
/*
    LinkedHashSet介绍:
        它是HashSet集合的子类, 特点是: 有序, 唯一.
 */
public class Demo05 {
    public static void main(String[] args) {
        //1.创建LinkedHashSet集合对象, 存储字符串"hello", "world", "java", "world"
        LinkedHashSet<String> lhs = new LinkedHashSet<>();
        lhs.add("hello");
        lhs.add("world");
        lhs.add("java");
        lhs.add("world");
        //2.遍历集合, 并将结果打印到控制台上.
        for (String s : lhs) {
            System.out.println(s);
        }
		//hello
        //world
        //java
    }
}

可变参数

  • 概述:

  • 它是JDK1.5的特性, 表示参数的个数可以变化的, 多用于 方法的形参列表

  • 格式:

    • public static int getSum(int... a): 在数据类型的后边加上 3个点
      
  • 注意事项:

    1. 可变参数的本质就是一个 数组.
    2. 方法的形参列表有且只能有一个可变参, 且可变参数必须放到形参列表的最后.
    3. 可变参数的参数个数至少 0 个, 至多 无数个.
案例: 演示可变参数
package com.itheima.demo02_change;

//案例: 演示可变参数.
/*
    可变参数简介:
        概述:
            它是JDK1.5的特性, 它的本质就是一个数组.
        格式:
            public static int  getSum(int... a)
            即: 在数据类型的后边加上 3个点
        注意事项:
            1. 可变参数的本质就是一个数组.
            2. 如果一个方法有多个参数, 其中包含可变参数, 那么可变参数要放最后.
               即: 方法的形参列表有且只能有一个可变参数, 且可变参数要放最后.
 */
public class Demo01 {
    public static void main(String[] args) {
        //2.在main方法中, 调用getSum()方法.
        int sum = getSum(1, 2, 3, 4, 5, 11);
        System.out.println(sum);
    }

    //1.定义getSum()方法, 用来获取n个整数的和(n可能是任意的一个数字).
    //public static int getSum(String b, int... a) {    //至少传入0个整数, 至多传入n个整数.
    public static int getSum(int... a) {    //至少传入0个整数, 至多传入n个整数.
        int sum = 0;
        for (int i = 0; i < a.length; i++) {
            sum += a[i];
        }
        return sum;
    }
}

Map集合

  • 概述:
    • 它表示双列集合的顶层接口, 存储的是 键值对元素, 其中键具有唯一性, 值可以重复.
    • 数据结构只针对于 有效, 且元素是 无序 的.
成员方法
  • public V put(K key,V value) 添加元素, 键存在就用新值覆盖旧值并返回旧值, 键不存在就直接添加并返回null.

  • public V remove(Object key) 根据键删除键值对元素, 返回删除之前的 值.

  • public void clear() 移除所有的键值对元素

  • public boolean containsKey(Object key) 判断集合是否包含指定的

  • public boolean containsValue(Object value) 判断集合是否包含指定的

  • public boolean isEmpty() 判断集合是否为空, 当且仅当长度为0返回true, 否则false

  • public int size() 集合的长度,也就是集合中键值对的个数

Map集合中的常用成员方法
package com.itheima.demo03_map;

import java.util.HashMap;
import java.util.Map;

//案例: 演示Map集合中的常用成员方法

public class Demo02 {
    public static void main(String[] args) {
        //1.定义Map集合, 键是丈夫, 值是妻子. (键值都是字符串类型).
        Map<String, String> hm = new HashMap<>();

        //2.分别测试上述的7个方法.
        //2.1 测试    V put(K key,V value)	            添加元素
        hm.put("杨过", "大雕");
        hm.put("尹志平", "小龙女");
        hm.put("张无忌", "赵敏");

        //2.2 测试V remove(Object key)	            根据键删除键值对元素
        String yg = hm.remove("杨过123");
        System.out.println("yg: " + yg);

        //2.3 测试  void clear()
        hm.clear();

        //2.4 测试  boolean containsKey(Object key)	    判断集合是否包含指定的键
        System.out.println(hm.containsKey("杨过"));
        System.out.println(hm.containsKey("乔峰"));

        //2.5 测试  boolean containsValue(Object value)	判断集合是否包含指定的值
        System.out.println(hm.containsValue("小龙女"));
        System.out.println(hm.containsValue("蛛儿"));

        //2.6 测试 boolean isEmpty()	          判断集合是否为空
        System.out.println(hm.isEmpty());

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

        //2.8 打印双列集合.
        System.out.println("hm: " + hm);

    }
}

获取功能相关方法
  • public Set keySet(); 获取所有键的集合,因为Map的键具有唯一性,所以返回值Set集合
  • public Collection values(); 获取所有值的集合,因为Map的值可以重复,所以返回值是Collection
  • public V get(K key); 根据获取其对应的.
  • public Set<Map.Entry<K, V>> entrySet(); 获取所有键值对对象的集合.
Map集合的获取功能
package com.itheima.demo03_map;

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

//案例: 演示Map集合的获取功能
/*
    涉及到的Map集合中的方法:
        public V get(K key)             根据键获取其对应的值.
        public Set<K>  keySet();        获取所有的键, 因为Map的键具有唯一性, 所以返回值Set集合.
        public Collection<V> values();  获取所有的值, 因为Map的值可以重复, 所以返回值是Collection
 */
public class Demo03 {
    public static void main(String[] args) {
        //1.定义Map集合, 键是丈夫, 值是妻子. (键值都是字符串类型).
        HashMap<String, String> hm = new HashMap<>();
        hm.put("乔峰", "阿朱");
        hm.put("虚竹", "梦姑");
        hm.put("段誉", "王语嫣");

        //2.先通过代码测试上述的3个方法. 即: get(), keySet(), values()

        //2.1 测试  public V get(K key)             根据键获取其对应的值.
        //分解版
        String value1 = hm.get("乔峰");
        System.out.println(value1);

        //合并版
        System.out.println(hm.get("乔峰"));
        System.out.println(hm.get("慕容复"));

        //2.2 测试  public Set<K>  keySet();        获取所有的键, 因为Map的键具有唯一性, 所以返回值Set集合.
        Set<String> keys = hm.keySet();
        for (String key : keys) {
            System.out.println(key);
        }
        System.out.println("-------------------");

        //2.3 测试 public Collection<V> values();  获取所有的值, 因为Map的值可以重复, 所以返回值是Collection
        Collection<String> values = hm.values();
        for (String value : values) {
            System.out.println(value);
        }
		
		//测试public Set<Map.Entry<K, V>> entrySet();	获取所有键值对 对象的集合.
		System.out.println(hm.entrySet());
    }
}

Map集合的遍历方式一: 根据键获取其对应的值
  • 具体步骤:
    1. 获取到所有的键的集合. Map#keySet()
    2. 遍历, 获取到每一个键. 增强for, 迭代器
    3. 根据键获取其对应的值. Map#get(K key)
package com.itheima.demo03_map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

//案例: 演示Map集合的遍历方式一: 根据键获取其对应的值.

public class Demo04 {
    public static void main(String[] args) {
        //1.定义Map集合, 键是丈夫, 值是妻子. (键值都是字符串类型).
        HashMap<String, String> hm = new HashMap<>();
        //2.往集合中添加3对键值对元素.
        hm.put("乔峰", "阿朱");
        hm.put("虚竹", "梦姑");
        hm.put("段誉", "王语嫣");
        //3.遍历Map集合.
        //3.1. 获取到所有的键的集合.
        Set<String> keys = hm.keySet();
        //方式一: 增强for
        //3.2 遍历, 获取到每一个键
        for (String key : keys) {
            //3.3 根据键获取其对应的值.
            String value = hm.get(key);
            System.out.println(key + "..." + value);
        }
        System.out.println("--------------------------");

        //方式二: 普通迭代器
        Iterator<String> it = keys.iterator();
        while (it.hasNext()) {
            String key = it.next();
            System.out.println(key + "..." + hm.get(key));
        }
    }
}
Map集合的遍历方式二: 根据键值对对象获取其对应的键和值
  • 具体步骤:
    1. 获取到所有的 键值对对象 的集合.
    2. 遍 - Map#entrySet(), 即: public Set<Map.Entry<K, V>> entrySet(); Map集合中获取所有键值对对象的方法.
    2. 遍历, 获取到每一个 键值对对象. 增强for, 迭代器
    3. 根据 键值对对象 获取其对应的. Map.Entry中的方法:getKey(), getValue()
  • 小细节:
    Map.Entry 是内部接口的写法, 即: Map是外部接口, Entry是Map接口中的内部接口.
package com.itheima.demo03_map;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

//案例: 演示Map集合的遍历方式二: 根据键值对对象获取其对应的键和值.
/*
    具体步骤:
        1. 获取到所有的 键值对对象 的集合.            Map#entrySet(), 即:       public Set<Map.Entry<K, V>>  entrySet();  Map集合中获取所有键值对对象的方法.
        2. 遍历, 获取到每一个 键值对对象.             增强for, 迭代器
        3. 根据 键值对对象 获取其对应的键和值.        Map.Entry中的方法: getKey(), getValue()

    小细节:
        Map.Entry 是内部接口的写法, 即: Map是外部接口, Entry是Map接口中的内部接口.
 */
public class Demo05 {
    public static void main(String[] args) {
        //1.定义Map集合, 键是丈夫, 值是妻子. (键值都是字符串类型).
        HashMap<String, String> hm = new HashMap<>();
        //2.往集合中添加3对键值对元素.
        hm.put("乔峰", "阿朱");
        hm.put("虚竹", "梦姑");
        hm.put("段誉", "王语嫣");
        //3.遍历Map集合.
        //方式一: 增强for
        //3.1 获取到所有的 键值对对象 的集合.
        Set<Map.Entry<String, String>> entrys = hm.entrySet();      //需要导入: import java.util.Map;
        //Set<Entry<String, String>> entrys = hm.entrySet();        //需要导入: import java.util.Map.Entry;

        //3.2 遍历, 获取到每一个 键值对对象.
        //Map.Entry<String, String>:  就是键值对对象的数据类型
        //String                      就是字符串的数据类型
        for (Map.Entry<String, String> entry : entrys) {
            //3.3  根据 键值对对象 获取其对应的键和值.
            System.out.println(entry.getKey() + "..." + entry.getValue());
        }
        System.out.println("----------------------------");
		
        //方式二: 迭代器
        //3.1 获取到所有的 键值对对象 的集合.
        Iterator<Map.Entry<String, String>> it = entrys.iterator();
        //3.2 遍历, 获取到每一个 键值对对象.
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            //3.3  根据 键值对对象 获取其对应的键和值.
            System.out.println(entry.getKey() + "..." + entry.getValue());
        }
    }
}
Map集合案例: 键是String, 值是Student

JavaBean类:学生类

package com.ithiema.api.demo;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) 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;
    }

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

测试类

package com.itheima.demo04_exercise;

import com.itheima.pojo.Student;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//Map集合案例: 键是String, 值是Student
public class Demo01 {
    public static void main(String[] args) {
        //1.创建HashMap集合, 键是学号(String), 值是学生对象(Student).
        HashMap<String, Student> hm = new HashMap<>();
        //2.往HashMap集合中添加3组数据.
        hm.put("黑马001", new Student("乔峰",36));
        hm.put("黑马002", new Student("虚竹",29));
        hm.put("黑马003", new Student("段誉",21));

        //hm.put("黑马003", new Student("虚竹",29));

        //3.通过两种方式, 遍历HashMap集合.
        //方式一: 根据键获取其对应的键和值.
        Set<String> keys = hm.keySet();
        for (String key : keys) {
            System.out.println(key + "..." + hm.get(key));
        }
        System.out.println("-------------------------");

        //方式二: 根据键值对获取其对应的键和值.
        Set<Map.Entry<String, Student>> entrys = hm.entrySet();
        for (Map.Entry<String, Student> entry : entrys) {
            System.out.println(entry.getKey() + "..." + entry.getValue());
        }
    }
}
Map集合案例: 键是Student, 值是String
package com.itheima.demo04_exercise;

import com.itheima.pojo.Student;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//Map集合案例: 键是Student, 值是String
//结论: HashMap保证键的唯一性依赖: hashCode(), equals()方法.
public class Demo02 {
    public static void main(String[] args) {
        //1.创建HashMap集合, 键是学生对象(Student), 值是居住地(String).
        HashMap<Student, String> hm = new HashMap<>();
        //2.往HashMap集合中添加3组数据.
        hm.put(new Student("乔峰", 36), "北京");
        hm.put(new Student("虚竹", 29), "上海");
        hm.put(new Student("段誉", 21), "广州");

        //hm.put(new Student("段誉", 21), "深圳");

        //3.通过两种方式, 遍历HashMap集合.
        //方式一: 根据键获取其对应的键和值.
        Set<Student> keys = hm.keySet();
        for (Student key : keys) {
            System.out.println(key + "..." + hm.get(key));
        }
        System.out.println("-------------------------");

        //方式二: 根据键值对获取其对应的键和值.
        Set<Map.Entry<Student, String>> entrys = hm.entrySet();
        for (Map.Entry<Student, String> entry : entrys) {
            System.out.println(entry.getKey() + "..." + entry.getValue());
        }
    }
}
Map案例: ArrayList嵌套HashMap集合
package com.itheima.demo04_exercise;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//Map案例: ArrayList嵌套HashMap集合.
public class Demo03 {
    public static void main(String[] args) {
        //1.定义ArrayList<HashMap<String, String>>集合, 存储三个元素, 每个元素都是一个双列集合, 具体如下:
        ArrayList<HashMap<String, String>> list = new ArrayList<>();
        //2.第一个双列集合, 记录的信息如下:
        // 孙策 大乔
        // 周瑜 小乔
        HashMap<String, String> sgyy = new HashMap<>();
        sgyy.put("孙策", "大乔");
        sgyy.put("周瑜", "小乔");

        //3.第二个双列集合, 记录的信息如下:
        // 郭靖 黄蓉
        // 杨过 大雕
        HashMap<String, String> sdxl = new HashMap<>();
        sdxl.put("郭靖", "黄蓉");
        sdxl.put("杨过", "大雕");

        //4.第三个双列集合, 记录的信息如下:
        // 令狐冲 任盈盈
        // 林平之 岳灵珊
        HashMap<String, String> xajh = new HashMap<>();
        xajh.put("令狐冲", "任盈盈");
        xajh.put("林平之", "岳灵珊");

        //5.把上述的三个双列集合当做元素对象, 添加到ArrayList集合中.
        list.add(sgyy);
        list.add(sdxl);
        list.add(xajh);

        //6.遍历ArrayList集合, 输出每个元素.
        //方式一: 根据键获取值.
        //6.1 遍历ArrayList集合, 获取每一个元素: HashMap<String, String>
        for (HashMap<String, String> hm : list) {
            //6.2 因为ArrayList集合的每个元素还是一个双列集合, 所以我们接着遍历.
            Set<String> keys = hm.keySet();
            //6.3 遍历, 获取双列集合的每一个键.
            for (String key : keys) {
                System.out.println(key + "..." + hm.get(key));
            }
            System.out.println();
        }
        System.out.println("---------------------------");
        //方式二: 根据键值对对象获取键和值.
        //6.1 遍历ArrayList集合, 获取每一个元素: HashMap<String, String>
        for (HashMap<String, String> hm : list) {
            //6.2 因为ArrayList集合的每个元素还是一个双列集合, 所以我们接着遍历.
            Set<Map.Entry<String, String>> entrys = hm.entrySet();
            //6.3 遍历, 获取双列集合的每一个键.
            for (Map.Entry<String, String> entry : entrys) {
                System.out.println(entry.getKey() + "..." + entry.getValue());
            }
            System.out.println();
        }

    }
}
Map案例: HashMap嵌套ArrayList
package com.ithiema.api.demo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//Map案例: HashMap嵌套ArrayList
public class Demo18 {
    public static void main(String[] args) {
        //1.创建一个HashMap集合,存储三个键值对元素,键表示书名(String),值是书中人物名(ArrayList<String>)
        HashMap<String, ArrayList<String>> list = new HashMap<>();
        //2.第一个ArrayList集合的元素: (三国演义)
        // 诸葛亮
        // 赵云
        ArrayList<String> sgyy = new ArrayList<>();
        sgyy.add("诸葛亮");
        sgyy.add("赵云");

        //3.第二个ArrayList集合的元素: (西游记)
        // 唐僧
        // 孙悟空
        ArrayList<String> xyj = new ArrayList<>();
        xyj.add("唐僧");
        xyj.add("孙悟空");

        //4.第三个ArrayList集合的元素: (水浒传)
        // 武松
        // 鲁智深
        ArrayList<String> shz = new ArrayList<>();
        shz.add("武松");
        shz.add("鲁智深");

        //5. 把元素填充到双列集合中.
        list.put("三国演义", sgyy);
        list.put("西游记", xyj);
        list.put("水浒传", shz);

        //6.遍历HashMap集合, 输出每一个元素.
        //方式一: 根据键获取值.
        //6.1 获取所有的键.
        Set<String> keys = list.keySet();
        //6.2 遍历, 获取到每一个键:  String
        for (String key : keys) {
            //6.3 根据键获取其对应的值: ArrayList<String>, 接着遍历.
            ArrayList<String> values = list.get(key);
            //6.5 因为值还是一个单列集合, 所以接着遍历.
            for (String value : values) {
                //6.6 获取到每一个具体的值, 然后输出.
                System.out.println(key + " " + value);
            }
        }


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

        //方式二: 根据键值对对象获取键和值.
        //6.1 获取所有的键.
        Set<Map.Entry<String, ArrayList<String>>> entrys = list.entrySet();
        //6.2 遍历, 获取到每一个键:  String
        for (Map.Entry<String, ArrayList<String>> entry : entrys) {
            String key = entry.getKey();
            //6.3 获取值: ArrayList<String>, 接着遍历.
            ArrayList<String> values = entry.getValue();
            //6.4 因为值还是一个单列集合, 所以接着遍历.
            for (String value : values) {
                //6.5 获取到每一个具体的值, 然后输出.
                System.out.println(key + " " + value);
            }
        }
    }
}
Map集合案例: 通过字符串中每个字符的次数

代码实现_详细版

package com.itheima.demo04_exercise;

import java.util.*;

//Map集合案例: 通过字符串中每个字符的次数.
public class Demo05_代码实现_详细版 {
    public static void main(String[] args) {
        /*
            1.键盘录入一个字符串,要求统计字符串中每个字符出现的次数。
            2.举例:键盘录入“aababcabcdabcde” 在控制台输出:“a(5)b(4)c(3)d(2)e(1)”
         */
        //1. 创建Scanner对象.
        Scanner sc = new Scanner(System.in);
        //2. 提示用户录入一个字符串, 并接收.
        System.out.println("请录入一个字符串: ");
        String str = sc.nextLine();
        //3. 定义Map集合, 字符做键, 该字符对应的次数作为值.    即:  HashMap<Character, Integer>    a:3, b:1
        Map<Character, Integer> map = new HashMap<>();
        //Map<Character, Integer> map = new TreeMap<>();
        //4. 把字符串转成字符数组.
        char[] chs = str.toCharArray();
        //5. 遍历, 获取到每一个字符.
        for (char ch : chs) {
            //6. 判断该字符在双列集合中是否存在.
            if (!map.containsKey(ch)) {
                //6.1 不存在, 说明该字符是第一次出现, 就将其次数记录为1.
                map.put(ch, 1);
            } else {
                //6.2 存在, 说明该字符不是第一次出现, 就将其次数+1, 然后重新存储.
                int count = map.get(ch);
                map.put(ch, count + 1);
            }
        }
        //已知格式: a:3, b:1     目标格式: a(5)b(4)c(3)d(2)e(1)
        //7. 走到这里, Map集合记录的就是我们要的结果, 将其拼接成字符串.
        StringBuilder sb = new StringBuilder();
        Set<Character> keys = map.keySet();
        for (Character key : keys) {
            int count = map.get(key);
            sb.append(key).append("(").append(count).append(")");
        }
        //8. 打印结果.
        String result = sb.toString();
        System.out.println(result);
    }
}

合并版

package com.itheima.demo04_exercise;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

//Map集合案例: 通过字符串中每个字符的次数.
public class Demo05_代码实现_合并版 {
    public static void main(String[] args) {
        /*
            1.键盘录入一个字符串,要求统计字符串中每个字符出现的次数。
            2.举例:键盘录入“aababcabcdabcde” 在控制台输出:“a(5)b(4)c(3)d(2)e(1)”
         */
        //1. 定义Map集合, 字符做键, 该字符对应的次数作为值.    即:  HashMap<Character, Integer>    a:3, b:1
        Map<Character, Integer> map = new HashMap<>();
        //2. 提示录入, 然后遍历, 获取到每一个字符.
        System.out.println("请录入一个字符串: ");
        for (char ch : new Scanner(System.in).nextLine().toCharArray())
            //6. 判断该字符在双列集合中是否存在.
            map.put(ch, !map.containsKey(ch) ? 1 :  map.get(ch) + 1);

        //已知格式: a:3, b:1     目标格式: a(5)b(4)c(3)d(2)e(1)
        //7. 走到这里, Map集合记录的就是我们要的结果, 将其拼接成字符串.
        StringBuilder sb = new StringBuilder();
        for (Character key : map.keySet())
            sb.append(key).append("(").append( map.get(key)).append(")");
        //8. 打印结果.
        System.out.println(sb);
    }
}

Collections工具类

  • 概述
    • 它是用来操作集合工具类,提供了大量针对于集合操作方法
成员方法
  • public static void sort(List list) 将指定的列表按升序排序

  • public static void reverse(List<?> list) 反转指定列表中的元素的顺序

  • public static void shuffle(List<?> list) 随机置换

  • public static E max(List<?> list) 获取集合元素的最大值

  • public static E min(List<?> list) 获取集合元素的最小值

  • 对集合元素降序排列. 先升序, 后反转.
    Collections.sort(list);
    Collections.reverse(list);

方法详解案例
package com.itheima.demo05_collections;

import java.util.ArrayList;
import java.util.Collections;

public class Demo01 {
    public static void main(String[] args) {
        //1.定义ArrayList集合, 存储5个整数.
        ArrayList<Integer> list = new ArrayList<>();
        list.add(11);
        list.add(44);
        list.add(33);
        list.add(22);
        list.add(55);

        //2.分别测试上述的3个方法.
        //测试: public static void sort(List list)          对列表排序, 默认是升序
        Collections.sort(list);

        //测试:  public static void reverse(List list)       反转列表元素
        Collections.reverse(list);

        //对集合元素降序排列.    先升序, 后反转.
        Collections.sort(list);
        Collections.reverse(list);

        //测试  public static void shuffle(List list)       随机置换, 相当于洗牌.
        Collections.shuffle(list);

        //max(), min()
        System.out.println(Collections.max(list));
        System.out.println(Collections.min(list));

        //3. 打印List集合
        System.out.println("list: " + list);
    }
}
案例: 模拟斗地主发牌_无序的牌
package com.itheima.demo04_exercise;

import java.util.ArrayList;
import java.util.Collections;

//案例: 模拟斗地主发牌
public class Demo06_Poker_无序的牌 {
    public static void main(String[] args) {
        //1. 买牌.
        //搞一个牌盒, 用来装扑克牌.
        ArrayList<String> pokers = new ArrayList<>();
        //填充牌
        String[] colors = {"♥", "♠", "♦", "♣"};
        String[] numbers = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
        //遍历花色集合
        for (String color : colors) {   //"♥", "♠", "♦", "♣"
            //遍历点数集合
            for (String number : numbers) { //"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
                pokers.add(color + number);
            }
        }
        //添加大小王
        pokers.add("小王");
        pokers.add("大王");

        //2. 洗牌.
        Collections.shuffle(pokers);

        //3. 发牌.  三个玩家, 一个底牌
        ArrayList<String> lyf = new ArrayList<>();
        ArrayList<String> zly = new ArrayList<>();
        ArrayList<String> hg = new ArrayList<>();
        ArrayList<String> dipai = new ArrayList<>();

        //发牌思路: 1. 最后三张作为底牌.   2. 牌的索引是0到53的, 依次和3取余,  余数为0给第一个人, 余数为1给第二个人, 余数为3给第三个人.
        for (int i = 0; i < pokers.size(); i++) {
            String poker =  pokers.get(i);      //就是每一张牌.
            if (i >= pokers.size() - 3) {       //51, 52, 53
                dipai.add(poker);
            } else if (i % 3 == 0) {
                lyf.add(poker);
            }else if (i % 3 == 1) {
                zly.add(poker);
            }else if (i % 3 == 2) {
                hg.add(poker);
            }
        }

        //4, 看牌.
        lookPoker("刘亦菲", lyf);
        lookPoker("赵丽颖", zly);
        lookPoker("夯哥", hg);
        lookPoker("底牌", dipai);
    }

    //4. 定义方法, 用来看牌
    public static void lookPoker(String name, ArrayList<String> list) {
        System.out.print(name + "的牌是: ");
        for (String poker : list) {
            System.out.print(poker + " ");
        }
        System.out.println();
    }
}
案例: 模拟斗地主发牌_有序的牌
package com.itheima.demo04_exercise;

import java.util.*;

//案例: 模拟斗地主发牌_有序的牌
public class Demo07_有序的牌 {
    public static void main(String[] args) {
        //1. 买牌.
        //1.1 造牌盒, 键: 牌的编号,  值: 对应的牌, 规则: 编号越小, 牌越小.
        HashMap<Integer, String> pokers = new HashMap<>();
        //1.2 造牌盒, 记录所有牌的编号.
        ArrayList<Integer> list = new ArrayList<>();
        //1.3 造牌.
        String[] colors = {"♥", "♠", "♦", "♣"};
        String[] numbers = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
        //1.4 定义变量, 记录牌的索引
        int index = 0;
        //遍历点数集合
        for (String number : numbers) { //"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"
            //遍历花色集合
            for (String color : colors) {   //"♥", "♠", "♦", "♣"
                pokers.put(index, color + number);      //双列集合
                list.add(index++);                      //单列集合, 记录牌的编号
            }
        }
        //添加大小王
        pokers.put(index, "小王");      //双列集合
        list.add(index++);              //单列集合, 记录牌的编号
        pokers.put(index, "大王");      //双列集合
        list.add(index);                //单列集合, 记录牌的编号

        //2. 洗牌.  洗的是序号
        Collections.shuffle(list);

        //3. 发牌.
		//TreeSet集合的特点: 无序, 排序, 唯一.   可以对元素进行排序,默认升序。或者用ArrayList集合,然后用Collections#sort()方法排序
        TreeSet<Integer> lyf = new TreeSet<>();
        TreeSet<Integer> zly = new TreeSet<>();
        TreeSet<Integer> hg = new TreeSet<>();
        TreeSet<Integer> dipai = new TreeSet<>();
		
        //否则你要写:  Collections.sort(List集合);
        //具体的发牌规则
        //发牌思路: 1. 最后三张作为底牌.   2. 牌的索引是0到53的, 依次和3取余,  余数为0给第一个人, 余数为1给第二个人, 余数为3给第三个人.
        for (int i = 0; i < list.size(); i++) {
            int poker =  list.get(i);      //就是每一张牌.
            if (i >= list.size() - 3) {       //51, 52, 53
                dipai.add(poker);
            } else if (i % 3 == 0) {
                lyf.add(poker);
            }else if (i % 3 == 1) {
                zly.add(poker);
            }else if (i % 3 == 2) {
                hg.add(poker);
            }
        }

        //4. 看牌.
        //看所有人和底牌的 编号.
        /*System.out.println(lyf);
        System.out.println(zly);
        System.out.println(hg);
        System.out.println(dipai);*/

        //看具体的牌
        lookPoker("刘亦菲", lyf, pokers);
        lookPoker("赵丽颖", zly, pokers);
        lookPoker("夯哥", hg, pokers);
        lookPoker("底牌", dipai, pokers);
    }

    //4. 定义方法, 用来看牌

    /**
     * 根据玩家手中的编号找对应的牌.
     * @param name      玩家的名字
     * @param ts        玩家手中的牌的编号
     * @param pokers    双列集合, 记录的是 牌的编号和牌的关系, 规则: 编号越小, 牌越小.
     */
    public static void lookPoker(String name, TreeSet<Integer> ts, HashMap<Integer, String> pokers) {
        System.out.print(name + "的牌是: ");
        for (int pokerNumber : ts) {
            System.out.print(pokers.get(pokerNumber) + " ");
        }
        System.out.println();
    }
}

集合-部分方法总结

 集合的使用步骤:
	1. 创建集合对象.
	2. 创建元素对象.
	3. 把元素对象添加到集合中.
	4. 遍历集合. 
 
 集合的遍历方式:
	Collection集合:		//Collection, List, Set都有的.
		1. 增强for
		2. 普通迭代器
		3. 转数组遍历.	//凑数的, 了解即可.
		
	List体系独有的:
		1. 列表迭代器.
		2. 普通for循环.
	
	Map体系:
		1. 根据键找值. 				//普通迭代器, 增强for
		2. 根据键值对获取键和值.	//普通迭代器, 增强for
		
Collection接口中的成员方法:		//仓库
	add()
	remove()
	clear()
	contains()
	isEmpty()
	size()
	public Iterator iterator();		//根据集合对象, 获取其对应的迭代器对象.   根据仓库获取其对应的仓库管理员.
	
Iterator接口中的方法:		//仓库管理员.
	public boolean hasNext();
	public E next();
	
ListIterator接口中的成员方法:	//列表迭代器, 能解决并发修改异常.
	public boolean hasNext();
	public E next();

	public boolean hasPrevious();
	public E previous();	
	
List接口中的独有的成员方法:
	add()
	remove()
	set()
	get()		//这四个方法都是带索引的, 索引不存在会报 IndexOutOfBoundsException
	
LinkedList集合中独有的成员方法	
	//该类中的成员方法大多都是操作 集合的首尾元素的.
	addFirst();
	addLast();
	removeFirst();
	removeLast();
	getFirst();
	getLast();
	
	
Map接口中的成员方法: 	
	基本的成员方法:
		put()
		remove()
		clear()
		containsKey()
		containsValue()
		isEmpty()
		size()
	
	获取功能的成员方法:
		keySet()
		values()
		get()
		entrySet()

Collections工具类的方法
	shuffle()
	sort()
	reverse()
	max()
	min()
	sychronizedXxx()		//线程不安全的类 => 线程安全的类
	
数据结构:: 	先进后出.
	队列: 	先进先出.
	数组:	查询(修改), 增删相对较慢. 
	链表:	查询(修改)相对较慢, 增删快. 
	哈希表: 数组 + 链表, 增删改查都快.
	
	
集合的体系图:
	Collection集合:	//单列集合的顶层接口
		List体系:
			特点:
				有序, 可重复, 元素有索引.
			常用子类:
				ArrayList:	底层数据结构采用的是数组, 所以查询修改相对较快, 增删相对较慢.
				LinkedList: 底层数据结构采用的是链表, 所以查询修改相对较慢, 增删相对较快.
			
		Set体系:
			特点:
				无序, 唯一, 元素无索引.
			常用子类:
				HashSet: 底层数据结构采用的是哈希表, 增删改查都快, 线程不安全, 效率高.
				TreeSet: 底层采用的是二叉树结构, 可以对元素排序, 但是实际开发中, 排序操作我们会放到SQL中中, 所以它了解即可.
	
	Map集合:		//双列集合的顶层接口
		特点:
			存储的键值对元素, 键具有唯一性, 值可以重复, 数据结构只针对于键有效. 
		常用子类:
			HashMap: 底层数据结构采用的是哈希表, 增删改查都快, 线程不安全, 效率高.
			TreeMap:


什么时候使用哪种集合?	
	看需求, 看用单列还是双列.
		单列:
			看需求, 看是否要求唯一.: Set
					看需求, 看是否要对元素排序.: TreeSet: HashSet		//需求不明确, 用HashSet: List
					看需求, 看查询多还是增删多
						查询多: ArrayList	//需求不明确, 用 ArrayList
						增删多: LinkedList
		
		双列:
			看需求, 看是否要对 键 排序
				是: TreeMap: HashMap		//需求不明确, 用HashMap
	
	
集合其他相关知识:
	1. 匿名内部类.
		格式, 写法, 应用场景.
	2. LinkedHashSet集合:
		有序, 唯一,  数据结构: 链表 + 哈希表
	3. 哈希值问题:
		同一对象哈希值肯定相同, 不同对象哈希值一般不同(例如:  重地和通话, 儿女和农丰)
	4. 可变参数
		本质, 位置, 个数, 用法.
	5. Collections工具类
		shuffle(), sort(), reverse(), max(), min()
		
	
	
案例:
	1. ArrayList存储 字符串,  学生对象, 并遍历. 
		//4种方式.
	2. HashSet 存储 字符串,  学生对象, 并遍历. 
		//2种方式, 记得保证元素唯一性.
	3. HashMap案例:
		A. HashMap<String, Student>
		B. HashMap<Student, String>
		C. ArrayList<HashMap<String, String>>
		D. HashMap<String, ArrayList<String>>
		E. 统计每个字符出现的次数.
	4. 模拟斗地主发牌.	

clear()
contains()
isEmpty()
size()
public Iterator iterator(); //根据集合对象, 获取其对应的迭代器对象. 根据仓库获取其对应的仓库管理员.

Iterator接口中的方法: //仓库管理员.
public boolean hasNext();
public E next();

ListIterator接口中的成员方法: //列表迭代器, 能解决并发修改异常.
public boolean hasNext();
public E next();

public boolean hasPrevious();
public E previous();	

List接口中的独有的成员方法:
add()
remove()
set()
get() //这四个方法都是带索引的, 索引不存在会报 IndexOutOfBoundsException

LinkedList集合中独有的成员方法
//该类中的成员方法大多都是操作 集合的首尾元素的.
addFirst();
addLast();
removeFirst();
removeLast();
getFirst();
getLast();

Map接口中的成员方法:
基本的成员方法:
put()
remove()
clear()
containsKey()
containsValue()
isEmpty()
size()

获取功能的成员方法:
	keySet()
	values()
	get()
	entrySet()

Collections工具类的方法
shuffle()
sort()
reverse()
max()
min()
sychronizedXxx() //线程不安全的类 => 线程安全的类

数据结构:
栈: 先进后出.
队列: 先进先出.
数组: 查询(修改)快, 增删相对较慢.
链表: 查询(修改)相对较慢, 增删快.
哈希表: 数组 + 链表, 增删改查都快.

集合的体系图:
Collection集合: //单列集合的顶层接口
List体系:
特点:
有序, 可重复, 元素有索引.
常用子类:
ArrayList: 底层数据结构采用的是数组, 所以查询修改相对较快, 增删相对较慢.
LinkedList: 底层数据结构采用的是链表, 所以查询修改相对较慢, 增删相对较快.

	Set体系:
		特点:
			无序, 唯一, 元素无索引.
		常用子类:
			HashSet: 底层数据结构采用的是哈希表, 增删改查都快, 线程不安全, 效率高.
			TreeSet: 底层采用的是二叉树结构, 可以对元素排序, 但是实际开发中, 排序操作我们会放到SQL中中, 所以它了解即可.

Map集合:		//双列集合的顶层接口
	特点:
		存储的键值对元素, 键具有唯一性, 值可以重复, 数据结构只针对于键有效. 
	常用子类:
		HashMap: 底层数据结构采用的是哈希表, 增删改查都快, 线程不安全, 效率高.
		TreeMap:

什么时候使用哪种集合?
看需求, 看用单列还是双列.
单列:
看需求, 看是否要求唯一.
是: Set
看需求, 看是否要对元素排序.
是: TreeSet
否: HashSet //需求不明确, 用HashSet
否: List
看需求, 看查询多还是增删多
查询多: ArrayList //需求不明确, 用 ArrayList
增删多: LinkedList

	双列:
		看需求, 看是否要对 键 排序
			是: TreeMap
			否: HashMap		//需求不明确, 用HashMap

集合其他相关知识:
1. 匿名内部类.
格式, 写法, 应用场景.
2. LinkedHashSet集合:
有序, 唯一, 数据结构: 链表 + 哈希表
3. 哈希值问题:
同一对象哈希值肯定相同, 不同对象哈希值一般不同(例如: 重地和通话, 儿女和农丰)
4. 可变参数
本质, 位置, 个数, 用法.
5. Collections工具类
shuffle(), sort(), reverse(), max(), min()

案例:
1. ArrayList存储 字符串, 学生对象, 并遍历.
//4种方式.
2. HashSet 存储 字符串, 学生对象, 并遍历.
//2种方式, 记得保证元素唯一性.
3. HashMap案例:
A. HashMap<String, Student>
B. HashMap<Student, String>
C. ArrayList<HashMap<String, String>>
D. HashMap<String, ArrayList>
E. 统计每个字符出现的次数.
4. 模拟斗地主发牌.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值