Java_集合

一、集合的理解和好处

这里是引用
在这里插入图片描述

二、集合的框架体系

背下来:在这里插入图片描述
Collection 单列集合
Collection 接口有两个重要的子接口 LIst Set ,他们的实现子类都是单列集合
这里是引用

Map双列集合
Map接口的实现子类是双列集合,存放的K-V在这里插入图片描述

        //单列集合
        ArrayList arrayList = new ArrayList();
        arrayList.add("Jack");
        arrayList.add("tom");
        //双列集合
        HashMap hashMap = new HashMap();
        hashMap.put("NO1", "北京");
        hashMap.put("NO2", "上海");

三、Collection接口和常用方法

(一)Collection接口实现类的特点

这里是引用
这里是引用

		List a = new ArrayList();
        //add:添加单个元素
        a.add("jack");//自动装箱
        a.add(10);//自动装箱 list.add(new Integer(10))
        a.add(true);//自动装箱
        System.out.println("a=" + a);//a=[jack, 10, true]

        //remove:删除指定元素
        // (Object o)-->boolean  (int index)-->Object
        a.remove(1);//指定删除某个元素
        a.remove("jack");//指定删除某个元素
        System.out.println("a=" + a);//a=[true]
        //contains:查找元素是否存在
        System.out.println(a.contains(10));//false

        //size:获取元素个数
        System.out.println(a.size());//1

        //isEmpty:判断是否为空
        System.out.println(a.isEmpty());//false

        //clear:清空,把整个元素集合清空
        a.clear();
        System.out.println("a=" + a);//a=[]

        //addAll:添加多个元素
        ArrayList b = new ArrayList();
        b.add("红楼梦");
        b.add("三国演义");
        a.addAll(b);
        System.out.println("a=" + a);//a=[红楼梦, 三国演义]

        //containsAll:查找多个元素是否都存在
        System.out.println(a.containsAll(b));//T

        //removeAll:删除多个元素
        a.removeAll(b);
        System.out.println("a=" + a);//a=[]
        a.add("聊斋");//不是list2.add
        a.removeAll(b);
        System.out.println("a=" + a);//a=[聊斋]

(二)Collection接口遍历元素方式1-使用Iterator(迭代器)

这里是引用
在这里插入图片描述
在这里插入图片描述

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

public class CollectionIterator {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Collection col = new ArrayList();//向上转型
        col.add(new Book("三国演义","罗贯中",10.1));
        col.add(new Book("小李飞刀","古龙",5.1));
        col.add(new Book("红楼梦","曹雪芹",34.6));
        System.out.println("col=" + col);//col=[Book{name='三国演义', author='罗贯中', price=10.1}, Book{name='小李飞刀', author='古龙', price=5.1}, Book{name='红楼梦', author='曹雪芹', price=34.6}]

        //遍历col集合
        //1.先得到 col 对应的迭代器
        Iterator iterator = col.iterator();
        //2.使用while循环遍历
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);//obj=Book{name='三国演义', author='罗贯中', price=10.1}
                                            //obj=Book{name='小李飞刀', author='古龙', price=5.1}
                                            //obj=Book{name='红楼梦', author='曹雪芹', price=34.6}
        }//可按快捷键快速生成 itit while循环
        //ctrl + j 生成快捷模板
        //3. 当退出while循环后,这时iterator迭代器,指向最后的元素
        //iterator.next();//NoSuchElementException
        //4.如果希望再次遍历,需要重置迭代器//游标重置
        //第二次遍历
        iterator = col.iterator();
        while (iterator.hasNext()) {
            Object obj1 = iterator.next();
            System.out.println("obj1=" + obj1);//obj=Book{name='三国演义', author='罗贯中', price=10.1}
                                                //obj=Book{name='小李飞刀', author='古龙', price=5.1}
                                             //obj=Book{name='红楼梦', author='曹雪芹', price=34.6}
        }

    }
}
class Book {
    private String name;
    private String author;
    private double price;

    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

(三)Collection接口遍历元素方式2-for循环增强

这里是引用

        Collection col = new ArrayList();//向上转型
        col.add(new Book("三国演义","罗贯中",10.1));
        col.add(new Book("小李飞刀","古龙",5.1));
        col.add(new Book("红楼梦","曹雪芹",34.6));

        //1.使用增强for,在Collection集合
        //2.增强的for,底层仍是迭代器
        //3.增强for可以理解成就是简化版的迭代器遍历
        //4.快捷键 I
        for(Object book : col) {
            System.out.println("book" + book);//bookBook{name='三国演义', author='罗贯中', price=10.1}
                                                //bookBook{name='小李飞刀', author='古龙', price=5.1}
                                                //bookBook{name='红楼梦', author='曹雪芹', price=34.6}
        }

        //增强for,也可以直接用在数组使用
        int[] nums = {1, 8, 10, 90};
        for(int i : nums) {
            System.out.println("i="+ i);//i=1 i=8 i=10 i=90
        }

这里是引用

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

public class CollectionFor {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Dog("小黑狗", 3));
        list.add(new Dog("大黄",100));
        list.add(new Dog("大壮",8));
        for (Object dog :list) {
            System.out.println("dog= " + dog);//dog= Dog{name='小黑狗', age=3}
            //dog= Dog{name='大黄', age=100}
            //dog= Dog{name='大壮', age=8}
        }
        System.out.println("==== 迭代器 =====");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object dog =  iterator.next();
            System.out.println("dog= " +dog);//dog= Dog{name='小黑狗', age=3}
            //dog= Dog{name='大黄', age=100}
            //dog= Dog{name='大壮', age=8}
        }


    }
}
class Dog {
    private String name;
    private int 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;
    }

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

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

四、List接口和常用方法

(一)LIst接口基本介绍

这里是引用

在这里插入图片描述

 //1.List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复【案例】
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
        list.add("hsp");
        list.add("tom");
        System.out.println("list=" + list);//list=[jack, tom, mary, hsp, tom]

        //2.List集合中的每个元素都有其对应的顺序索引,即支持索引
        //索引从0开始
        System.out.println(list.get(4));//tom

(二)List接口的常用方法

在这里插入图片描述

		public static void main(String[] args) {
        List list= new ArrayList();
        list.add("张三丰");
        list.add("贾宝玉");
        //void add(int index, Objext ele):在index位置插入ele元素
        list.add(1, "你好");
        System.out.println("list=" + list);//list=[张三丰, 你好, 贾宝玉]
        //boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
        List list2= new ArrayList();
        list2.add("jack");
        list2.add("tom");
        list.addAll(1,list2);
        System.out.println("list=" + list);//list=[张三丰, jack, tom, 你好, 贾宝玉]
        //Object get(int index):获取指定index位置的元素
        //int indexOf(Object obj):返回obj在集合中首次出现的位置
        System.out.println(list.indexOf("tom"));//2
        //int lastIndexOf(Object obj):放回obj在当前集合中最后一次出现的位置
        list.add("你好");
        System.out.println("list=" + list);//list=[张三丰, jack, tom, 你好, 贾宝玉, 你好]
        System.out.println(list.lastIndexOf("你好"));//5
        //Object remove(int index):移除指点index位置的元素,并且返回此元素
        list.remove(5);
        System.out.println("list=" + list);//list=[张三丰, jack, tom, 你好, 贾宝玉]
        //Object set(int index, Object ele):设置指定index的位置元素为ele,相当于替换
        list.set(1,"马克");
        System.out.println("list=" + list);//list=[张三丰, 马克, tom, 你好, 贾宝玉]
        //List subList(int fromIndex, int toIndex):返回fromIndex到toIndex位置的子集合
        List returnlist = list.subList(0, 2);  // 0 <= subList < 2
        System.out.println("returnlist=" + returnlist);//returnlist=[张三丰, 马克]
    }

(三)List接口课堂练习

这里是引用

        List list= new ArrayList();
        for (int i = 0; i < 12; i++) {
            list.add("hello" + i);
        }
        System.out.println("list=" + list);
        list.add(1,"abcde");
        System.out.println("list=" + list);
        //获取第5个元素
        System.out.println("第五个元素=" + list.get(4));//第五个元素=hello3
        //删除第六个元素
        System.out.println("删除第六个元素");
        list.remove(5);
        System.out.println("list=" + list);
        //修改第七个元素
        System.out.println("修改第七个元素");
        list.set(6, "三国演义");
        System.out.println("list=" + list);
        //使用迭代器
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }

输出结果:
list=[hello0, hello1, hello2, hello3, hello4, hello5, hello6, hello7, hello8, hello9, hello10, hello11]
list=[hello0, abcde, hello1, hello2, hello3, hello4, hello5, hello6, hello7, hello8, hello9, hello10, hello11]
第五个元素=hello3
删除第六个元素
list=[hello0, abcde, hello1, hello2, hello3, hello5, hello6, hello7, hello8, hello9, hello10, hello11]
修改第七个元素
list=[hello0, abcde, hello1, hello2, hello3, hello5, 三国演义, hello7, hello8, hello9, hello10, hello11]
obj=hello0
obj=abcde
obj=hello1
obj=hello2
obj=hello3
obj=hello5
obj=三国演义
obj=hello7
obj=hello8
obj=hello9
obj=hello10
obj=hello11

(四)List的三种遍历方式 [ArrayList, ListedList, Vector]

在这里插入图片描述


        // List 接口的实现子类 Vetor LinkedList
        List list= new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("鱼香肉丝");
        list.add("北京烤鸭");
        //遍历
        //1.迭代器
        System.out.println("====迭代器=====");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj =  iterator.next();
            System.out.println(obj);
        }
        //2.增强for
        System.out.println("====增强for====");
        for (Object o :list) {
            System.out.println(o);
        }
        //3.普通for
        System.out.println("====普通for====");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

输出结果
迭代器
jack
tom
鱼香肉丝
北京烤鸭
增强for
jack
tom
鱼香肉丝
北京烤鸭
普通for
jack
tom
鱼香肉丝
北京烤鸭

运行类型互换ArrayList, ListedList, Vector也一样

    //List list= new ArrayList();
    //List list= new Vector();
    List list= new LinkedList();

(五)实现类的课堂练习2

在这里插入图片描述

import java.util.*;

public class ListMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Book("红楼梦", 100, "曹雪芹"));
        list.add(new Book("西游记", 10, "吴承恩"));
        list.add(new Book("水浒传", 9, "施耐庵"));
        list.add(new Book("三国演义", 80,"罗贯中"));
        for (Object o :list) {
            System.out.println(o);
        }
        //冒泡排序
        sort(list);
        System.out.println("====排序后===");
        for (Object o :list) {
            System.out.println(o);
        }

    }
    //静态方法
    //价格要求是从小到大
    public static void sort(List list) {
        for (int i =0; i <list.size()-1; i++) {
            for(int j = 0; j < list.size()-1-i; j++) {
                //取出对象Book
                Book book1 = (Book)list.get(j);
                Book book2 = (Book)list.get(j + 1);
                if(book1.getPrice() > book2.getPrice()) {
                    list.set(j, book2);
                    list.set(j + 1, book1);
                }
            }
        }
    }
}
class Book {
    private String name;
    private double price;
    private String author;

    public Book(String name, double price, String author) {
        this.name = name;
        this.price = price;
        this.author = author;
    }

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "名称:" + name + "\t\t" + "价格:" + price + "\t\t" + "作者:" + author;
    }
}

输出结果:
名称:红楼梦 价格:100.0 作者:曹雪芹
名称:西游记 价格:10.0 作者:吴承恩
名称:水浒传 价格:9.0 作者:施耐庵
名称:三国演义 价格:80.0 作者:罗贯中
==排序后=
名称:水浒传 价格:9.0 作者:施耐庵
名称:西游记 价格:10.0 作者:吴承恩
名称:三国演义 价格:80.0 作者:罗贯中
名称:红楼梦 价格:100.0 作者:曹雪芹

五、ArrayList底层结构和源码分析

(一)ArrayList的注意事项

在这里插入图片描述

		//ArrayList 是线程不安全的,可以看源码,没有synchronized
        // public boolean add(E e) {
        //        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //        elementData[size++] = e;
        //        return true;
        //    }
        ArrayList arrayList = new ArrayList();
        arrayList.add(null);
        arrayList.add("jack");
        arrayList.add(null);
        System.out.println(arrayList);

(二)ArrayList的底层操作机制源码分析(重点,难点

在这里插入图片描述

总结:
无参构造器:elementDate初始为0,则往后10->15->22 …1.5倍
指定大小构造器:如果elementDate指定为8,则往后8->12->18…1.5倍

这里是引用
在这里插入图片描述

(三)ArrayList的底层操作机制分析案例

在这里插入图片描述
这里是引用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、Vector底层结构和源码剖析

(一)Vector的基本介绍

在这里插入图片描述

synchronized:支持线程同步和互斥
集合始终只有一个线程操作,用ArrayList,效率高
集合有好多个线程操作,用Vector,是线程安全的,支持线程同步和互斥

(二)Vector和ArrayList的比较

这里是引用

七、LindedList底层结构

(一)LinkedList的全面说明

在这里插入图片描述
在这里插入图片描述

(二)LinkedList的底层操作机制

在这里插入图片描述
在这里插入图片描述

public class LinkedList01 {
    public static void main(String[] args) {
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node hsp = new Node("老韩");

        //连接三个节点,形成双向链表
        //jack -> tom -> hsp
        jack.next = tom;
        tom.next = hsp;
        //hsp -> tom -> jack
        hsp.pre = tom;
        tom.pre = jack;

        Node first = jack;//让first引用指向jack,就是双向链表的头结点
        Node last = hsp;//让last引用指向hsp,就是双向链表的头结点

        //演示,从头到尾进行遍历
        System.out.println("====从头到尾遍历=====");
        while (true) {
            if(first == null) {
                break;
            }
            //输出first 信息
            System.out.println(first);
            first = first.next;
        }

        //演示,从尾到头进行遍历
        System.out.println("====从尾到头遍历=====");
        while (true) {
            if(last == null) {
                break;
            }
            //输出last 信息
            System.out.println(last);
            last = last.pre;
        }

        //演示链表的添加对象/数据
        //在tom 和 老韩中加smith
        //1.先创建一个Node节点,name就是smith
        Node smith = new Node("smith");
        //下面就把smith加入到双线链表
        smith.next = hsp;
        smith.pre = tom;
        hsp.pre = smith;
        tom.next = smith;

        first = jack;//让first引用指向jack,就是双向链表的头结点

        //演示,从头到尾进行遍历
        System.out.println("====插入后从头到尾遍历=====");
        while (true) {
            if(first == null) {
                break;
            }
            //输出first 信息
            System.out.println(first);
            first = first.next;
        }

        last = hsp;//让last重新指向最后一个节点
        //演示,从尾到头进行遍历
        System.out.println("====插入后从尾到头遍历=====");
        while (true) {
            if(last == null) {
                break;
            }
            //输出last 信息
            System.out.println(last);
            last = last.pre;
        }

    }
}
//定义一个Node 类,Node对象,表示双向链表的一个节点
class Node {
    public Object item;//真正存放数据
    public Node next;//指向后一个节点
    public Node pre;//指向前一个节点

    public Node(Object name) {
        this.item = name;
    }

    @Override
    public String toString() {
        return "Node name=" + item;
    }
}

输出结果:

====从头到尾遍历=====
Node name=jack
Node name=tom
Node name=老韩
====从尾到头遍历=====
Node name=老韩
Node name=tom
Node name=jack
====插入后从头到尾遍历=====
Node name=jack
Node name=tom
Node name=smith
Node name=老韩
====插入后从尾到头遍历=====
Node name=老韩
Node name=smith
Node name=tom
Node name=jack

(三)LinkedList的增删改查案例

@SuppressWarnings({"all"})
public class LinkedListCRUD {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        System.out.println("linkedList=" + linkedList);//linkedList=[1]


        //演示删除
        linkedList.remove();//默认删除第一个
        System.out.println("linkedList=" + linkedList);//linkedList=[2, 3]

        //修改某个节点
        linkedList.set(1,666);
        System.out.println("linkedList=" + linkedList);//linkedList=[2, 666]

        //得到某个节点对象
        Object o = linkedList.get(0);
        System.out.println("linkedList=" + o);//linkedList=2

        //因为LinkedList是实现了List接口,遍历方式
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println("next=" + next);//next=2
                                                //next=666
        }
        //增强for
        System.out.println("====增强for=====");
        for (Object o1 :linkedList) {
            System.out.println("o1=" + o1);
        }
        System.out.println("=====LinkedList普通for===");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }


        //增加源码码阅读
        //1.LinkedList linkedList = new LinkedList();
        /*
        * public LinkedList() {}
        *
        * 2.这是LinkedList的属性first = null  last = null
        * 3.指向    public boolean add(E e) {
                        linkLast(e);
                        return true;
                    }
         *4.将新的节点,加入到双向链表的最后
         * void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
        * */

        /*
        * 删除源码分析
        * 1   public E remove() {
        return removeFirst();
    }
        * private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }
        *
        *
        * */
    }

输出结果:

linkedList=[1, 2, 3]
linkedList=[2, 3]
linkedList=[2, 666]
linkedList=2
next=2
next=666
====增强for=====
o1=2
o1=666
=====LinkedList普通for===
2
666

(四)ArrayList和LinkedList比较

这里是引用

八、Set接口和常用方法

(一)Set接口基本介绍

这里是引用
在这里插入图片描述
在这里插入图片描述

@SuppressWarnings({"all"})
public class SetMethod {
    public static void main(String[] args) {
        //1.以Set接口的实现类 HashSet 来讲解Set 接口的方法
        //2.set接口的实现类的对象(Set接口对象),不能存放重复元素,可以添加null,
        //3.set接口对象存放对象无序(即添加的顺序和取出的顺序不一致)
        //4.取出的顺序是固定的
        Set set = new HashSet();
        set.add("john");
        set.add("lucy");
        set.add("john");//重复
        set.add("jack");
        set.add("hsp");
        set.add("mary");
        set.add(null);
        set.add(null);//重复
        for (int i = 0; i < 10; i++) {
            System.out.println("set=" + set);
        }
        //遍历
        //方式1:使用迭代器
        System.out.println("====使用迭代器====");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }
        
        //删除
        set.remove(null);

        //方式2:增强for
        System.out.println("====增强for====");
        for (Object o :set) {
            System.out.println("set=" + set);
        }

    }
}

输出结果:

set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
set=[null, hsp, mary, john, lucy, jack]
====使用迭代器====
obj=null
obj=hsp
obj=mary
obj=john
obj=lucy
obj=jack
====增强for====
set=[hsp, mary, john, lucy, jack]
set=[hsp, mary, john, lucy, jack]
set=[hsp, mary, john, lucy, jack]
set=[hsp, mary, john, lucy, jack]
set=[hsp, mary, john, lucy, jack]

(二)HashSet的全面说明

这里是引用

  Set hashSet = new HashSet();
        hashSet.add(null);
        hashSet.add(null);
        System.out.println("hashSet=" + hashSet);//hashSet=[null]
   
public class HashSet01 {
    public static void main(String[] args) {
        HashSet set = new HashSet();
        //说明
        //1.在执行add方法后,会返回一个boolean值
        //2.如果添加成功,放回 true,否则返回false
        System.out.println(set.add("john"));//T
        System.out.println(set.add("lucy"));//T
        System.out.println(set.add("john"));//F
        System.out.println(set.add("jack"));//T
        System.out.println(set.add("Ruse"));//T
        //3.可以通过remove删除哪个对象
        set.remove("john");
        System.out.println("set=" + set);//set=[Ruse, lucy, jack]

        //
        set = new HashSet();
        System.out.println("set=" + set);//set=[]

        //4.HashSet 不能存放相同元素或数据
        set.add("lucy");
        set.add("lucy");//加入不了
        set.add(new Dog("tom"));
        set.add(new Dog("tom"));//new 地址不一样可以加入成功
        System.out.println("set=" + set);//set=[name=tom, name=tom, lucy]

        //在加深一下,非常经典面试题
        set.add(new String("hsp"));//加进去
        set.add(new String("hsp"));//加入不了
        System.out.println("set=" + set);//set=[hsp, name=tom, name=tom, lucy]
    }
}
class Dog {
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "name=" + name;
    }
}

这里留个坑

(三)HashSet底层机制说明

这里是引用

@SuppressWarnings({"all"})
public class HashSetStructure {
    public static void main(String[] args) {
        //模拟一个HashMap底层结构 (HashSet 的底层是HashMap)
        //1.创建一个数组,数组的类型是Node[]
        //2.有些人直接把Node[] 数组称为表
        Node[] table = new Node[16];
        System.out.println("table=" + table);
        //3.创建节点
        Node john = new Node("john", null);
        table[2] = john;
        Node jack = new Node("jack", null);
        john.next = jack;//将jack节点挂载到john
        Node rose = new Node("Rose", null);
        jack.next = rose;//将rose节点挂载到jack后
        Node lucy = new Node("lucy", null);
        table[3] = lucy;
        System.out.println("table=" + table);

        System.out.println("table=" + table);
    }
}
class Node { //节点,存储数据,可以指向下一个节点
    Object item;//存放数据
    Node next;//指向下一个节点

    public Node(Object item, Node next) {
        this.item = item;
        this.next = next;
    }
}

这里是引用

分析源码卡住

分析HashSet的添加元素底层时候如何实现==(hash() + equals())==

1.先获取元素的哈希值(hashCode方法)。
2.对哈希值进行运算,得到一个索引值极为要存放在哈希表中的位置号。
3.如果该位置上没有其他元素,则直接存放。
4.如果该位置上已经有其他元素,则需要进行equals判断,如果相等,则不再添加,,如果不等,则以链表的方式添加。

在这里插入图片描述

(四)HashSet课堂练习1

这里是引用

在这里插入图片描述

        @SuppressWarnings({"all"})
public class HashSetExercise {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee("milan", 18));
        hashSet.add(new Employee("smith", 28));
        hashSet.add(new Employee("milan", 18));
        System.out.println("hashSet=" + hashSet);
    }
}
//创建Employee
class Employee {
    private String name;
    private int age;

    public Employee(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 "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //如果name和age值相同,则返回相同的hash值
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

输出结果:

hashSet=[Employee{name='smith', age=28}, Employee{name='milan', age=18}]

(五)HashSet课堂练习2

在这里插入图片描述

(六)LInkedHashSet的全面说明

添加元素是有序的

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

@SuppressWarnings({"all"})
public class LinkedHashSetSource {
    public static void main(String[] args) {
        Set set = new LinkedHashSet();
        set.add(new String("AA"));
        set.add(456);
        set.add(456);
        set.add(new Customer("刘", 1001));
        set.add(123);
        set.add("HSP");
        System.out.println("set=" + set);//set=[AA, 456, com.hspedu.set_.Customer@1b6d3586, 123, HSP]
        //1.LInkedHashSet 加入顺序和取出顺序一致
        //2.LinkedHashSet底层维护的是一个LInkedHashMap(是HashMap子类)
        //3.LinkedHashSet 底层结构(数组table+双向链表)
        //4.添加第一次时,直接将 数组table 扩容到16,存放的节点类型是
        //5.数组是 HashMap$Node[] 存放的元素/数据是LinkedHashMap$Entry类型
    }
}
class Customer {
    private String name;
    private int no;

    public Customer(String name, int no) {
        this.name = name;

在这里插入图片描述

public static void main(String[] args) {
LinkedHashSet linkedHashSet = new LinkedHashSet();
linkedHashSet.add(new Car(“奥拓”, 1000));
linkedHashSet.add(new Car(“奥迪”, 300000));
linkedHashSet.add(new Car(“法拉利”, 10000000));
linkedHashSet.add(new Car(“奥迪”, 300000));
linkedHashSet.add(new Car(“保时捷”, 70000000));
linkedHashSet.add(new Car(“奥迪”, 300000));
//没重写
// System.out.println(“linkedHashSet=” + linkedHashSet);//都可以
//linkedHashSet=[
//Car{name=‘奥拓’, price=1000.0},
//Car{name=‘奥迪’, price=300000.0},
//Car{name=‘法拉利’, price=1.0E7},
//Car{name=‘奥迪’, price=300000.0},
//Car{name=‘保时捷’, price=7.0E7},
//Car{name=‘奥迪’, price=300000.0}]

    //重写equals
    System.out.println("linkedHashSet=" + linkedHashSet);
    //linkedHashSet=[
    //Car{name='奥拓', price=1000.0},
    //Car{name='奥迪', price=300000.0},
    //Car{name='法拉利', price=1.0E7},
    //Car{name='保时捷', price=7.0E7}]
}

}
class Car {
private String name;
private double price;

public Car(String name, double price) {
    this.name = name;
    this.price = price;
}

public String getName() {
    return name;
}

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

public double getPrice() {
    return price;
}

public void setPrice(double price) {
    this.price = price;
}

@Override
public String toString() {
    return "\nCar{" +
            "name='" + name + '\'' +
            ", price=" + price +
            '}';
}
//重写equals 和hashCode方法
//当name 和 peice 相同时,返回hashCode值,equals放回t

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Car car = (Car) o;
    return Double.compare(car.price, price) == 0 &&
            Objects.equals(name, car.name);
}

@Override
public int hashCode() {
    return Objects.hash(name, price);
}

}

九、Map接口和常用方法

(一)Map接口实现类的特点

在这里插入图片描述
在这里插入图片描述

{
        //接口实现类的特点,使用实现类HashMap实现
        //1.Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
        //2.Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
        //3.Map中的key不允许重复,原因和HashSet一样
        //4.Map中的value可以重复
        //5.Map中的key可以为 null,value也可以为null,注意key为null只能一次,value可以多次null
        //6.常用String类作为Map的key
        //7.key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value
        Map map = new HashMap();
        map.put("no1", "韩顺平");//k-v
        map.put("no2", "张无忌");//k-v//无序map={no2=张无忌, no1=韩顺平}
        map.put("no1", "张三丰");//key-value//当有相同的key,就等价于替换// map={no2=张无忌, no1=张三丰}
        map.put("no3", "张三丰");//map={no2=张无忌, no1=张三丰, no3=张三丰}
        map.put(null, null);//k-v//map={no2=张无忌, null=null, no1=张三丰, no3=张三丰}
        map.put(null,"abc");//等价替换//map={no2=张无忌, null=abc, no1=张三丰, no3=张三丰}
        map.put("no4",null);
        map.put("no5",null);//map={no2=张无忌, null=abc, no1=张三丰, no4=null, no3=张三丰, no5=null}
        map.put(1, "赵敏");//map={no2=张无忌, null=abc, no1=张三丰, 1=赵敏, no4=null, no3=张三丰, no5=null}
        map.put(new Object(), "金毛狮王");//map={no2=张无忌, null=abc, no1=张三丰, 1=赵敏, no4=null, no3=张三丰, no5=null, java.lang.Object@1b6d3586=金毛狮王}
        System.out.println(map.get("no1"));//张三丰

        System.out.println("map=" + map);
    }

(二)Map接口的特点

在这里插入图片描述
在这里插入图片描述

(三)Map接口的常用方法

在这里插入图片描述

@SuppressWarnings({"all"})
public class MapMethod {
    public static void main(String[] args) {
        //演示map接口常用方法
        Map map = new HashMap();
        map.put("邓超", new Book("", 100));
        map.put("邓超", "孙俪");
        map.put("王宝强", "马蓉");
        map.put("宋吉", "马蓉");
        map.put("刘玲播", null);
        map.put(null, "刘亦菲");
        map.put("鹿晗","关晓彤");
        System.out.println("map=" + map);//map={邓超=孙俪, null=刘亦菲, 刘玲播=null, 王宝强=马蓉, 宋吉=马蓉, 鹿晗=关晓彤}

        //remove:根据键删除映射关系
        map.remove(null);
        System.out.println("map=" + map);//map={邓超=孙俪, 刘玲播=null, 王宝强=马蓉, 宋吉=马蓉, 鹿晗=关晓彤}

        //get:根据键获取值
        map.get("鹿晗");
        Object val = map.get("鹿晗");
        System.out.println("val=" + val);//val=关晓彤

        //size:获取元素个数
        System.out.println("k-v=" + map.size());//k-v=5

        //isEmpty:判断个数是否为0
        System.out.println(map.isEmpty());//false

        //clear:清空
        map.clear();
        System.out.println("map=" + map);//map={}

        //containsKey:查找键是否存在
        System.out.println(map.containsKey("hsp"));//false

    }
}
class Book {
    private String name;
    private int num;

    public Book(String name, int num) {
        this.name = name;
        this.num = num;
    }

(四)Map接口遍历方法

在这里插入图片描述
在这里插入图片描述

@SuppressWarnings({"all"})
public class MapFor {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("邓超", "孙俪");
        map.put("王宝强", "马蓉");
        map.put("宋吉", "马蓉");
        map.put("刘玲播", null);
        map.put(null, "刘亦菲");
        map.put("鹿晗","关晓彤");

        //第一组:先取出所有的Key,通过Key取出对应的Value
        Set keySet = map.keySet();
        //1.(1)增强for
        System.out.println("=====1.(1)增强for=====");
        for (Object key :keySet) {
            System.out.println(key + "-" + map.get(key));
        }
        //1.(2)通过迭代器
        System.out.println("=====1.(2)通过迭代器=====");
        Iterator iterator = keySet.iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            System.out.println(key + "-" + map.get(key));
        }
        //第二组:把所有的values取出
        Collection values = map.values();
        //这里可以使用所有的Collections使用的遍历方法
        //2.(1)增强for
        System.out.println("====2.(1)增强for 取出所有的values=====");
        for (Object value :values) {
            System.out.println(value);
        }
        //2.(2)迭代器
        System.out.println("=====2.(2)通过迭代器  取出所有的values======");
        Iterator iterator1 = values.iterator();
        while (iterator1.hasNext()) {
            Object value = iterator1.next();
            System.out.println(value);
        }

        //第三组:通过EntrySet来获取 k-v
        Set entrySet = map.entrySet();// EntrySet<Map.Entry<K.V>>
        //(1)增强for
        System.out.println("===3.(1)使用EntrySet=== 增强for");
        for (Object entry :entrySet) {
            //将entry 转成 Map.Entry
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }
        //(2)迭代器
        System.out.println("=====3.(2)通过迭代器===entrySet==");
        Iterator iterator2 = entrySet.iterator();
        while (iterator2.hasNext()) {
            Object entry =  iterator2.next();
            //System.out.println(next.getClass());//HashMap$Node --实现--> Map.Entry(getKey,getValue)
            //向下转型 Map.Entry
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }


    }
}

输出结果:

=====1.(1)增强for=====
邓超-孙俪
null-刘亦菲
刘玲播-null
王宝强-马蓉
宋吉-马蓉
鹿晗-关晓彤
=====1.(2)通过迭代器=====
邓超-孙俪
null-刘亦菲
刘玲播-null
王宝强-马蓉
宋吉-马蓉
鹿晗-关晓彤
====2.(1)增强for 取出所有的values=====
孙俪
刘亦菲
null
马蓉
马蓉
关晓彤
=====2.(2)通过迭代器  取出所有的values======
孙俪
刘亦菲
null
马蓉
马蓉
关晓彤
===3.(1)使用EntrySet=== 增强for
邓超-孙俪
null-刘亦菲
刘玲播-null
王宝强-马蓉
宋吉-马蓉
鹿晗-关晓彤
=====3.(2)通过迭代器===entrySet==
邓超-孙俪
null-刘亦菲
刘玲播-null
王宝强-马蓉
宋吉-马蓉
鹿晗-关晓彤

(五)Map接口课堂练习

在这里插入图片描述

@SuppressWarnings({"all"})
public class MapExercise {
    public static void main(String[] args) {
        Map hashMap = new HashMap();
        hashMap.put(1, new Emp("jack", 300000,1));
        hashMap.put(2, new Emp("tom", 210000,2));
        hashMap.put(3, new Emp("milan", 120000,3));

        //两种遍历方式
        //1. 使用keySet -> 增强for
        Set keySet = hashMap.keySet();
        System.out.println("===1. 使用keySet -> 增强for==");
        for (Object key :keySet) {
            //先获取value
            Emp emp =(Emp) hashMap.get(key);
            if(emp.getSal() > 180000) {
                System.out.println(emp);
            }
        }
        //2.使用EntrySet ->迭代器
        Set entrySet = HashMap.entrySet();
        System.out.println("====//2.使用EntrySet ->迭代器=====");
        Iterator iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            //通过entry取得key和value
            Emp emp = (Emp)entry.getValue();
                    if(emp.getSal() > 18000) {
                        System.out.println(emp);
                    }
        }

    }
}
class Emp {
    private String name;
    private double sal;
    private int id;

    public Emp(String name, double sal, int id) {
        this.name = name;
        this.sal = sal;
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", id=" + id +
                '}';
    }
}

(六)HashMap小结

在这里插入图片描述

(七)HashMap底层机制及源码剖析

在这里插入图片描述
在这里插入图片描述

(八) HashTable的基本介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(九)Map接口实现类-Properties

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

     Properties properties = new Properties();
        properties.put("john", 100);//k-v
//        properties.put(null, 100);//k-v 不能为空,继承了HashTable//NullPointerException
//        properties.put("john", null);//k-v 不能为空,继承了HashTable
        properties.put("lucy", 100);
        properties.put("lic", 100);
        properties.put("lic", 88);//替换
        System.out.println("properties=" + properties);//properties={john=100, lic=88, lucy=100}
    

(十)总结-开发中如何选择集合现实类(记住

在这里插入图片描述

TressMap:

  //1.调用无参构造器,排序是无序的
        //TreeSet treeSet = new TreeSet();//treeSet=[a, jack, sp, tom]
        //2.按照字母大小排
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //按照字母先后排序
                return ((String) o1).compareTo((String) o2);//treeSet=[a, jack, sp, tom]
                //按照字母长度排序
                //return ((String) o1).length() - ((String) o2).length();//treeSet=[a, sp, tom, jack]
            }
        });
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("sp");
        treeSet.add("a");
        //treeSet.add("a");//算字母排序,再加入一个相同的值,底层源码进不去,不是替换
        treeSet.add("abc");//算长度,加不进去,长度和"tom"长度一样
        System.out.println("treeSet=" + treeSet);
    

TreeMap:

在这里插入图片描述

  //使用默认构造器
        //TreeMap treeMap = new TreeMap();//无序//treeMap={jack=杰克, kristina=可牛斯提诺, smith=史密斯, tom=汤姆}

        TreeMap treeMap = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //按照k 字母先后排序
                return ((String) o1).compareTo((String) o2);//treeMap={jack=杰克, kristina=可牛斯提诺, smith=史密斯, tom=汤姆}
                //按照k 长度排序
                //return ((String) o1).length() - ((String) o2).length();//treeMap={tom=汤姆, jack=杰克, smith=史密斯, kristina=可牛斯提诺}
            }
        });
        treeMap.put("jack", "杰克");//k-v
        treeMap.put("tom", "汤姆");
        treeMap.put("kristina", "可牛斯提诺");
        treeMap.put("smith", "史密斯");
        treeMap.put("hsp","韩顺平");//按照长度,加入不了,不是替换,是换了value值//treeMap={tom=韩顺平, jack=杰克, smith=史密斯, kristina=可牛斯提诺}
                                    //按照字母,可以进去
        System.out.println("treeMap=" + treeMap);
    

(十一)Collection工具类

在这里插入图片描述

    //创建ArrayList 集合,用于测试
        List list = new ArrayList();
        list.add("tom");
        list.add("smith");
        list.add("king");
        list.add("milan");
        //reverse(List): 反转 List中的元素
        Collections.reverse(list);//list=[milan, king, smith, tom]
        //shuffle(List): 对List集合元素进行随机排序
        Collections.shuffle(list);//list=[smith, king, milan, tom]
        //sort(List):根据字母从小到大排序
        Collections.sort(list);
        //sort:按照字符串长度排序
        Collections.sort(list, new Comparator() {//list=[tom, king, milan, smith]

            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o1).length() - ((String) o2).length();
            }
        });
        //swap(list, int, int) 交换排序
        Collections.swap(list, 0, 1);//list=[king, tom, milan, smith]

        System.out.println("list=" + list);
   

这里是引用

    //创建ArrayList 集合,用于测试
        List list = new ArrayList();
        list.add("tom");
        list.add("smith");
        list.add("king");
        list.add("milan");
        
        //reverse(List): 反转 List中的元素
        Collections.reverse(list);//list=[milan, king, smith, tom]
        
        //shuffle(List): 对List集合元素进行随机排序
        Collections.shuffle(list);//list=[smith, king, milan, tom]
        
        //sort(List):根据字母从小到大排序
        Collections.sort(list);
        
        //sort:按照字符串长度排序
        Collections.sort(list, new Comparator() {//list=[tom, king, milan, smith]

            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o1).length() - ((String) o2).length();
            }
        });
        
        //swap(list, int, int) 交换排序
        Collections.swap(list, 0, 1);//list=[king, tom, milan, smith]
        
        //Object max(Collection):根据元素的自然顺序,字母开头最大,返回给定的集合中的最大元素
        //System.out.println("自然顺序最大元素=" + Collections.max(list));
        //System.out.println("list=" + list);
        
        //Object max(COllection,Comparator):根据 Comparator指定的顺序,返回给定集合中的最大元素
        //比如,我们要返回长度最大的元素
        Object maxObject = Collections.max(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o1).length() - ((String) o2).length();
            }
        });
        System.out.println("最大长度元素=" + maxObject);//最大长度元素=milan
        
        //int frequency(Collection, Object):返回指定集合中的指定元素的出现次数
        System.out.println("tom出现的次数=" + Collections.frequency(list, "tom"));//tom出现的次数=1
        
        //void copy(List dest, List src):将src 中的内容复制到dest中
        ArrayList dest = new ArrayList();
        //为了完成一个完整的拷贝,我们需要给dest赋值,大小和list.size()一样
        for (int i = 0; i < list.size(); i++) {
            dest.add("");
        }
        Collections.copy(dest, list);
        System.out.println("dest=" + dest);//dest=[king, tom, milan, smith]
        
        //boolean replaceArr(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值
        Collections.replaceAll(list, "tom" ,"汤姆");
        System.out.println("list=" + list);//list=[king, 汤姆, milan, smith]
    

(十)集合家庭作业

在这里插入图片描述

public class Properties_ {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new news("新冠确诊病例超千万,数百万印度教教信徒赴恒河”圣浴“引民众担忧"));
        arrayList.add(new news("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生"));
        int size = arrayList.size();
        for (int i =size - 1; i >= 0; i--) {
            news news =(news) arrayList.get(i);
            System.out.println(processTitle(news.getTitle()));
        }
    }
    //专门写个标题,处理实现新闻标题
    public static String processTitle(String title) {
        if(title == null) {
            return "";
        }
        if(title.length() > 15) {
            return title.substring(0, 15) + "...";//[0, 15)
        } else {
            return title;
        }
    }
}
class news {
    private String title;
    private String contents;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContents() {
        return contents;
    }

    public void setContents(String contents) {
        this.contents = contents;
    }

    public news(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "title=" + title;
    }
}

输出结果:

男子突然想起2个月前钓的鱼还在...
新冠确诊病例超千万,数百万印度...

在这里插入图片描述

@SuppressWarnings({"all"})
public class Properties_ {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        Car car = new Car("宝马", 400000);
        Car car1 = new Car("宾利", 5000000);
        //1.add:添加单个元素
        arrayList.add(car);
        arrayList.add(car1);
        //System.out.println(arrayList);//[Car{name='宝马', price=400000.0}, Car{name='宾利', price=5000000.0}]
        //2.remove
        arrayList.remove(car);
        //System.out.println(arrayList);//[Car{name='宾利', price=5000000.0}]
        //3.contains:查找是否存在
        //System.out.println(arrayList.contains(car));//false

        //4.size:大小
        System.out.println(arrayList.size());//1

        //5.isEmpty 判断是否为空
        System.out.println(arrayList.isEmpty());//false

        //6.clear 清空
        //7.addAll:添加多个元素
        arrayList.addAll(arrayList);
        System.out.println(arrayList);//[Car{name='宾利', price=5000000.0}, Car{name='宾利', price=5000000.0}]

        //8.contaidAll
        arrayList.containsAll(arrayList);

        //9.removeAll


    }
}
class Car {
    private String name;
    private double price;

    public Car(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

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

这里是引用

 Map m = new HashMap();
        m.put("jack", 650);//int->Integer
        m.put("tom", 1200);
        m.put("smith", 2900);
        //System.out.println(m);//{tom=1200, smith=2900, jack=650}
        m.put("jack", 2600);//替换
        //System.out.println(m);//{tom=1200, smith=2900, jack=2600}
        //为所有员工加薪100元
        //keySet
        Set keySet = m.keySet();
        for(Object obj:keySet) {
            m.put(obj, (Integer)m.get(obj) + 100);
        }System.out.println(m);//{tom=1300, smith=3000, jack=2700}
        //遍历
        System.out.println("====遍历====");
        Set entrySet = m.entrySet();
        //迭代器
        Iterator iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry)iterator.next();
            System.out.println(entry.getKey() + "-" + entry.getValue());
        }
        System.out.println("==遍历所有的工资==");
        Collection values = m.values();
        for (Object value :values) {
            System.out.println(value);
        }
{tom=1300, smith=3000, jack=2700}
====遍历====
tom-1300
smith-3000
jack-2700
==遍历所有的工资==
1300
3000
2700

这里是引用

这里是引用
这里是引用

这里是引用

这里是引用
这里是引用

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值