韩顺平 Java集合 自学笔记(Java30天基础)

韩顺平 Java集合 自学笔记

  • Java集合
    • 集合的理解和好处
      • 数组的不足之处
      • 集合的好处
  • Collection接口实现类的特点
    • Collection接口的遍历形式
      • 使用迭代器Iterator(迭代器)
        • 迭代器的执行原理
      • Itrator接口的方法
      • for循环增强遍历
      • 课堂练习:
  • List接口和常用方法
      • List接口是Collection接口的子接口
      • List的三种遍历方式
      • 课堂练习2
    • ArrayList底层结构和源码分析
    • Vector底层机构和源码剖析
      • Vector的基本介绍
    • Vector和List比较
    • LinkedList底层结构
    • LinkedList的底层操作机制
    • LinkedList和ArrayList的区别
  • Set接口和常用方法
    • Set接口的遍历方式
    • HashSet的全面说明
    • HashSet的底层机制
      • 课堂练习
      • 课后练习
    • LinkedHashSet
  • Map集合
    • Map接口实现类的特点
    • Map的常用方法
    • Map接口遍历方法
      • 课后练习
      • HashMap小结
    • HashMap底层机制以及源码剖析
      • 模拟HashMap触发扩容、树化情况
      • Map接口实现类-Hashtable
    • Properties
  • 集合选型
  • TreeSet
    • TreeMap
  • Collections工具类
    • 排序操作(均为static方法)
    • 查找和替换
  • 课后作业
    • 课后作业1:
    • 课后习题2
    • 课后习题3
    • 简答题
    • 课后作业5:
    • 课后作业7

Java集合

集合的理解和好处

数组的不足之处

(1)长度开始时必须指定,而且一旦指定,不能更改。
(2)保存的必须为同一类型的元素。
(3)使用数组进行增加元素的示意代码比较麻烦。

数组扩容,不灵活,比较麻烦,实例如下:

package com.arrayEx;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/10/3 18:18
 * 数组扩容:灵活性差,比较麻烦
 */
public class ArrayExample {
    @Test
    public void expandArray() {
        Person[] people = new Person[3];
        // 添加几个元素进去
        people[0] = new Person("小明", 10);
        people[1] = new Person("小刚", 20);
        people[2] = new Person("小红", 30);

        for (Person person : people) {
            System.out.println(person);
        }

        System.out.println("-----------扩容后----------");

        Person[] peopleAdd = new Person[5];
        for (int i = 0; i < people.length; i++) {
            peopleAdd[i] = people[i];
        }

        peopleAdd[3] = new Person("梅梅", 40);
        peopleAdd[4] = new Person("兰兰", 50);

        for (Person person : peopleAdd) {
            System.out.println(person);
        }
    }
}

class Person {
    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 Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

集合的好处

(1)可以动态保存任意多个对象,使用比较方便
(2)提供了一系列方便的操作对象的方法:add、remove、set、get等
(3)使用集合添加,删除新元素更加简洁

集合类图
韩顺平 Java集合 自学笔记(Java30天基础)_第1张图片

Collection 接口图
韩顺平 Java集合 自学笔记(Java30天基础)_第2张图片

Map接口图
韩顺平 Java集合 自学笔记(Java30天基础)_第3张图片

1.集合主要是两组(单列集合、双列集合)
2.Collection接口有两个重要的子接口List Set 它们的实现子类都是单列集合
3.Map接口的实现子类 是双列集合,存放的 Key-Value

Collection接口实现类的特点

public interface Collection extends Iterable

(1)Collection实现子类可以存放多个元素,每个元素可以是Object
(2)有些Collection的实现类,可以存放重复的元素,有些不可以
(3)有些Collection的实现类是有序的(List),有些是无序的(Set)–这里说的有序和无序是指取出的顺序是否和放入顺序一致
(4)Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的

示例:

package com.CollectionExercise;

import org.junit.Test;

import java.util.*;

/**
 * @author wty
 * @date 2022/10/3 18:33
 */
public class CollectionExp {
    @Test
    @SuppressWarnings({"all"})
    public void knowCollection() {
        //Collection
        //Map
        //LinkedHashMap
        //ArrayList
        // 创建一个ArrayList(单列集合)
        List list = new ArrayList();
        // add添加单个元素
        list.add("hello");
        list.add(10); // list.add(new Integer(10))
        list.add(true);
        list.add(new Integer(30));
        list.add(new String("word"));
        System.out.println(list);

        // remove删除元素
        list.remove(0);// 删除第一个元素hello
        list.remove("word"); //指定删除对象
        System.out.println(list);

        // contains查找某个元素是否存在
        System.out.println(list.contains(true));
        System.out.println(list.contains("hello"));

        // size获取元素个数
        System.out.println("size:" + list.size());

        // isEmpty是否为空
        System.out.println(list.isEmpty());

        // clear清空
        list.clear();
        System.out.println(list);

        // addAll 可以添加集合、多个元素
        List list2 = new ArrayList();
        list2.add(35.5d);
        list2.add(45.5f);
        list.addAll(list2);
        System.out.println(list);

        // containsAll 查找多个元素是否存在
        System.out.println(list.containsAll(list2));

        // removeall 删除多个元素
        List list3 = new ArrayList();
        list3.add("特别的爱特别的你");
        list.addAll(list3);
        System.out.println("removeall前:" + list);

        list.removeAll(list3);
        System.out.println("removeall后:" + list);

    }
}

Collection接口的遍历形式

使用迭代器Iterator(迭代器)

(1)Itrator对象称为迭代器,只要用于遍历Collection集合中的元素。
(2)所有实现了Collection接口的集合类都有一个Iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器
(3)Iterator仅用于遍历集合,Iterator本身并不存放对象

迭代器的执行原理

韩顺平 Java集合 自学笔记(Java30天基础)_第4张图片

Itrator接口的方法

示例:

package com.ItratorExercise;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/4 11:45
 */
public class ItratorExercise {
    @Test
    @SuppressWarnings({"all"})
    public void getItrator() {
        Collection arrayList = new ArrayList();
        arrayList.add(new Book("三国演义", "罗贯中", 42.99));
        arrayList.add(new Book("西游记", "吴承恩", 38.5));
        arrayList.add(new Book("水浒传", "施耐庵", 66.66));

        System.out.println("直接输出:" + arrayList);
        System.out.println("------------------");

        // 先得到对应的迭代器
        Iterator iterator = arrayList.iterator();
        // 快捷键itit
        // ctrl + j :所有快捷键的快捷键

        while (iterator.hasNext()) { // 判断是否还有数据
            // 返回下一个元素,类型是Object
            Object next = iterator.next();
            System.out.println(next);
        }

        // 当退出while循环后,这时迭代器指向最后一个元素
        //报错 iterator.next(); // java.util.NoSuchElementException

        // 如果希望再次遍历,需要重置迭代器
        arrayList.add("今天天气不错");
        System.out.println("重置迭代器之后………………");
        iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }
    }
}

class Book {
    private String name;
    private String author;
    private double 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;
    }

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

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

for循环增强遍历

增强for循环,可以替代itrator迭代器,特点:增强for就是简化版的iterator,本质一样。只能用于遍历集合或者数组

基本语法:

for(元素类型 元素名:集合名或数组名){
 访问元素
}

示例:

package com.StrongFor;

import org.junit.Test;

import java.util.ArrayList;

/**
 * @author wty
 * @date 2022/10/4 14:18
 */
public class StrongFor {
    @Test
    public void strongFor() {

        ArrayList arrayList = new ArrayList();
        arrayList.add(new Teacher("王老师", 45, 1.68));
        arrayList.add(new Teacher("李老师", 25, 1.58));
        arrayList.add(new Teacher("刘老师", 27, 1.78));

        // 使用增强for循环,在Collection集合
        // 底层仍然是迭代器
        // 增强for循环,可以理解成简化版的迭代器
        // I快捷键
        for (Object o : arrayList) {
            System.out.println(o);
        }


        // 增强for循环也可以在数组使用
        int[] nums = {1, 8, 9, 10};
        for (int num : nums) {
            System.out.println(num);
        }

    }
}

class Teacher {
    private String name;
    private int age;
    private double height;

    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 double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public Teacher(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

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

课堂练习:

编写程序CollectionExercise
(1)创建3个Dog{name,age}对象,放入到ArrayList中,赋给List使用
(2)用迭代器和增强for循环两种方式来遍历
(3)重写Dog的toString方法,输出name和age

package com.CollectionAndIterator;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/4 14:33
 */
public class CollectionExerciseAndIterator {
    @Test
    public void cllectionExerciseAndIterator() {
        List list = new ArrayList();
        list.add(new Dog("大黄", 1));
        list.add(new Dog("小贝", 2));
        list.add(new Dog("来福", 3));

        // 迭代器
        System.out.println("迭代器");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }

        System.out.println("增强for循环");
        // 增强for循环
        for (Object o : list) {
            System.out.println(o);
        }

    }
}

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接口是Collection接口的子接口

(1)List集合类中元素有序(即添加顺序和取出顺序一致)、并且可以重复
(2)List集合中的每个元素都有其对应的顺序索引,即支持索引
(3)List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
(4)List接口的常用实现类有:ArrayList、LinkedList和Vector

List接口和常用方法
(1)add 在index位置插入元素
(2)addAll 从index位置开始将所有元素添加进来
(3)get 获取指定index位置的元素
(4)indexOf 返回在集合中首次出现的位置
(5)lastIndexOf 返回在当前集合中末次出现的位置
(6)remove 移除index位置的元素,并返回此元素
(7)set 设置指定index位置的元素(替换)
(8)subList 返回一个范围位置中的子集合

示例:

package com.ListExercise;
	
	import org.junit.Test;
	
	import java.util.ArrayList;
	import java.util.List;
	
	/**
	 * @author wty
	 * @date 2022/10/4 15:04
	 */
	public class ListMethod {
	    @Test
	    public void ListMethodExercise() {
	        List list = new ArrayList();
	        list.add("张三丰");
	        list.add("贾宝玉");
	
	        // 插入一个元素
	        list.add(1, "林黛玉");
	        System.out.println(list);
	
	        // 插入一个集合
	        List list2 = new ArrayList();
	        list2.add("Jack");
	        list2.add("Tom");
	        list.addAll(1, list2);
	        System.out.println(list);
	
	        // 获取集合中索引的值
	        System.out.println("get(2):" + list.get(2)); // Tom
	
	        // 返回首个出现的位置
	        System.out.println(list.indexOf("林黛玉")); // 3
	
	        // 返回末次出现的位置
	        list.add("林黛玉");
	        System.out.println(list.lastIndexOf("林黛玉")); // 5
	
	        // 移除元素并且输出该元素
	        list.remove(5);
	        System.out.println(list);
	
	        // 替换
	        list.set(1, "王宝强");
	        System.out.println(list);
	
	        // 返回范围值内的子集合[0,3)所以只有0,1,2三个元素
	        List listReturn = list.subList(0, 3);
	        System.out.println(listReturn);
	    }
	}

练习:

package com.ListExercise;
	
	import org.junit.Test;
	
	import java.util.ArrayList;
	import java.util.Iterator;
	import java.util.List;
	
	/**
	 * @author wty
	 * @date 2022/10/4 15:17
	 */
	public class ListExercise02 {
	    @Test
	    public void ListExer02() {
	        List list = new ArrayList();
	        list.add("1 你好");
	        list.add("2 hello world");
	        list.add("3 10");
	        list.add("4 今天天气不错");
	        list.add("5 开心");
	        list.add("6 难过");
	        list.add("7 悲伤");
	        list.add("8 喜悦");
	        list.add("9 幸福");
	        list.add("10 自豪");
	        System.out.println(list);
	
	        list.add(1, "韩顺平教育");
	        System.out.println("在2号位置插入:" + list);
	
	        System.out.println("获取第5个元素:" + list.get(4));
	        list.remove(5);
	        System.out.println("删除第6个元素后:" + list);
	        list.set(6, "很悲伤");
	        System.out.println("修改第7个元素后:" + list);
	
	
	        Iterator iterator = list.iterator();
	        while (iterator.hasNext()) {
	            Object next = iterator.next();
	            System.out.println(next);
	        }
	    }
	}

List的三种遍历方式

(1)方式一:使用迭代器
(2)方式二:增强for循环
(3)方式三:使用普通for循环

package com.ListExercise;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/4 18:08
 */
public class Bianli {
    @Test
    public void getBianli() {
        List list = new ArrayList();
        list.add("Jack");
        list.add("Tom");
        list.add("鱼香肉丝");
        list.add("北京烤鸭");

        // 迭代器遍历
        System.out.println("-----迭代器遍历:-----");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }

        // 增强for循环遍历
        System.out.println("------增强for循环遍历:-------");
        for (Object o : list) {
            System.out.println(o);
        }

        // 普通for循环遍历(类似数组)
        System.out.println("-----普通for循环遍历:-------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

    }

    @Test
    public void getBianli02() {
        List vector = new Vector();
        vector.add("Jack");
        vector.add("Tom");
        vector.add("鱼香肉丝");
        vector.add("北京烤鸭");

        // 迭代器遍历
        System.out.println("-----迭代器遍历:-----");
        Iterator iterator = vector.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }

        // 增强for循环遍历
        System.out.println("------增强for循环遍历:-------");
        for (Object o : vector) {
            System.out.println(o);
        }

        // 普通for循环遍历(类似数组)
        System.out.println("-----普通for循环遍历:-------");
        for (int i = 0; i < vector.size(); i++) {
            System.out.println(vector.get(i));
        }

    }
}

课堂练习2

韩顺平 Java集合 自学笔记(Java30天基础)_第5张图片

冒泡排序排列集合中对象的某个属性

package com.ListExercise;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/4 18:19
 */
public class ListExercise03 {
    @Test
    public void listExercise03() {
        List list = new ArrayList();
        list.add(new Book("红楼梦", 100, "曹雪芹"));
        list.add(new Book("西游记", 10, "吴承恩"));
        list.add(new Book("水浒传", 9, "施耐庵"));
        list.add(new Book("三国演义", 80, "罗贯中"));
        list.add(new Book("西游记", 10, "吴承恩"));

        // 正常顺序
        System.out.println("-----正常顺序-----");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        // 冒泡排序之后的顺序,从小到大
        BubbleSort(list);

        System.out.println("-----冒泡排序之后-------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }

    public void BubbleSort(List list) {
        int size = list.size();
        for (int i = 0; i < size - 1; i++) {
            for (int j = 0; j < size - i - 1; j++) {
                Object ob1 = list.get(j);
                Object ob2 = list.get(j + 1);
                // 向下转型
                Book book1 = (Book) ob1;
                Book book2 = (Book) ob2;

                if (book1.getPrice() > book2.getPrice()) {
                    list.set(j + 1, book1);
                    list.set(j, book2);
                }
            }

        }
    }
}

class Book {
    private String name;
    private double price;
    private String 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;
    }

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

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

ArrayList底层结构和源码分析

(1).ArrayList可以放所有的元素甚至是空元素,可以放入多个空值。
(2).ArrayList是由数组来实现数据存储的。
(3).ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高),在多线程下,不建议用ArrayList。
(4).ArrayList中维护了一个Object类型的数组elementData
transient Object[] elementData
transient:短暂的,瞬间的,表示该属性不会被序列化
(5).当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量是0,第1次添加,则扩容elementData为10,如需再次扩容,则扩容elementData为1.5倍
(6).如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍

Vector底层机构和源码剖析

Vector的基本介绍

(1)Vector类的定义说明:
public class Vector
extends AbstractList
implements List, RandomAccess, Cloneable,Serializable
(2)Vector底层也是一个对象数组,protected Object[] elementData
(3)Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized
(4)在开发中,需要线程同步安全时,优先考虑用Vector

Vector和List比较

韩顺平 Java集合 自学笔记(Java30天基础)_第6张图片

LinkedList底层结构

(1)LinkedList实现了双向链表双端队列特点
(2)可以添加任意元素(元素可以重复),包括null
(3)线程不安全,没有实现同步

LinkedList的底层操作机制

(1)LinkedList底层维护了一个双向链表
(2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点
(3)每个节点(Node对象),里面又维护了prev,next,item三个属性,其中通过prev指向前一个,通过next指向后一个节点 ,最终实现双向链表。
(4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高
韩顺平 Java集合 自学笔记(Java30天基础)_第7张图片

模拟一个双向链表简单示例:

package com.ListExercise;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/10/6 14:45
 * 模拟一个双向链表
 */
public class LinkedListExercise02 {
    @Test
    public void getLinked() {
        Linked one = new Linked("One");
        Linked two = new Linked("Two");
        Linked four = new Linked("Four");


        one.next = two;
        two.next = four;

        four.pre = two;
        two.pre = one;

        Linked first = one; // 定义头结点
        System.out.println("----从头到尾遍历-----");
        while (true) {
            if (first == null) {
                break;
            }
            System.out.println(first);
            first = first.next;
        }

        Linked last = four; // 定义尾结点
        System.out.println("----从尾到头遍历-----");
        while (true) {
            if (last == null) {
                break;
            }
            System.out.println(last);
            last = last.pre;
        }

        // 插入一个元素
        Linked three = new Linked("Three");
        two.next = three;
        four.pre = three;

        three.next = four;
        three.pre = two;

        first = one;
        System.out.println("插入元素3之后,从头到尾遍历");
        while (true) {
            if (null == first) {
                break;
            }
            System.out.println(first);
            first = first.next;
        }

        last = four;
        System.out.println("插入元素3之后,从尾到头遍历");
        while (true) {
            if (null == last) {
                break;
            }
            System.out.println(last);
            last = last.pre;
        }


    }
}

class Linked {
    public Linked pre;
    public Linked next;
    public Object name;

    public Linked(Object name) {
        this.name = name;
    }

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

关于LinkedList源码分析

package com.ListExercise;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/6 15:01
 */
public class LinkedListCRUD {
    @Test
    public void linkedListCRUD() {
        LinkedList list = new LinkedList();
        list.add(100);
        list.add(200);
        list.add(300);
        System.out.println(list);

        // 修改,把200更改成400
        System.out.println(list.set(1, 400)); // 200

        // 删除400
        System.out.println(list.remove(1)); // 400

        // 查找第2个元素
        System.out.println(list.get(1));

        // 迭代器遍历
        System.out.println("----迭代器遍历----");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }

        System.out.println("增强for循环遍历");
        for (Object o : list) {
            System.out.println(o);
        }

        System.out.println("普通for循环遍历");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

    }
}

LinkedList和ArrayList的区别

Set接口和常用方法

(1)无序(添加和取出的顺序不一致),没有索引
(2)不允许元素重复,所以最多包含一个null
(3)JDK API中Set接口的实现类有:

Set接口的遍历方式

同Collection的遍历方式一样,因为Set接口是Collection接口的子接口。
1.可以使用迭代器
2.增强for循环
3.不能使用索引的方式来获取

常用方法示例;

package com.SetExercise;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/6 17:24
 */
public class SetMethod {
    @Test
    public void SetMethodEx() {
        // 以Set接口的实现类,HashSet为例
        // Set接口的实现类的对象(Set接口对象)不能存放重复元素
        // 可以添加一个null
        // Set接口对象存放数据、对象是无序的(添加顺序和取出顺序不一致)
        // 取出的顺序是固定的
        Set set = new HashSet();
        set.add("小明");
        set.add("小芳");
        set.add("小刚");
        set.add("小明");
        set.add(null);
        set.add(null);
        System.out.println(set);

        // 遍历
        //方式1;迭代器
        System.out.println("---迭代器---");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }

        // 增强for循环
        System.out.println("---增强for循环---");
        for (Object o : set) {
            System.out.println(o);
        }

        System.out.println("size:" + set.size());
        System.out.println("是否为空:" + set.isEmpty());
        System.out.println("是否包含元素[小刚]:" + set.contains("小刚"));
        System.out.println("remove:" + set.remove("小刚"));
        System.out.println("remove:" + set.remove(null));
        System.out.println(set);
    }
}

HashSet的全面说明

(1)HashSet实现了Set接口
(2)HashSet实际上是HashMap
(3)可以存放null值,但是只能有一个null
(4)HashSet不保证元素是有序的,取决于hash后,再确定索引的结果(不保证元素存放和取出顺序一致)
(5)不能有重复元素/对象。在前面Set接口使用已经讲过了

package com.SetExercise;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/10/6 18:14
 */
public class HashSetStructure {
    @Test
    public  void getHashSetStr(){
        // 模拟一个HashSet的底层(其实就是HashMap)
        // 创建一个Node数组,有些人称为table
        Node[] table = new Node[16];
        System.out.println("table:" + table);
        // 把john放在2的位置
        Node jhon = new Node("Jhon",null);
        table[2] = jhon;
        System.out.println("table:" + table);

        Node jack = new Node("Jack", null);
        jhon.next = jack; // 将jack挂载到johj后边
        System.out.println("table:" + table);

        // 继续把Rose挂载到Jack后面
        Node rose = new Node("Rose", null);
        jack.next = rose;
        System.out.println("table:" + table);

        // 把Lucy放到table表索引为3的位置
        Node lucy = new Node("Lucy", null);
        table[3] = lucy;

    }
}
// 结点,存储数据,可以指向下一个结点
class Node{
    Object item;// 存放数据
    Node next; // 指向下一个结点

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

HashSet的底层机制

分析:HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)
浓缩成6句话

  1. HashSet底层是HashMap
  2. 添加一个元素时,先得到hash值,会转成索引值
  3. 找到存储数据表table,看这个索引位置是否已经存放的有元素
  4. 如果没有,直接加入
  5. 如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则添加到最后
  6. 在JAVA 8 中,如果一条链表的元素个数,到达TREEIFY_THRESHOLD(默认是8),并且table的大小>= MIN_TREEIFY_CAPACITY(默认64)就进行树化(红黑树)
    韩顺平 Java集合 自学笔记(Java30天基础)_第8张图片

课堂练习

课后练习

equals和hashCode示例1:
韩顺平 Java集合 自学笔记(Java30天基础)_第9张图片

package com.SetExercise;

import org.junit.Test;

import java.util.HashSet;
import java.util.Objects;

/**
 * @author wty
 * @date 2022/10/7 14:50
 */
public class Employee {
    @Test
    public void employee() {
        HashSet hashSet = new HashSet();
        hashSet.add(new Workers("小明", 10));
        hashSet.add(new Workers("小红", 20));
        hashSet.add(new Workers("小明", 30));
        hashSet.add(new Workers("小刚", 40));
        hashSet.add(new Workers("小明", 10));
        System.out.println("size:" + hashSet.size());
        System.out.println(hashSet);
    }
}

class Workers {
    private String name;
    private int age;

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

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


    // 如果name和age相同,要返回相同的哈希值
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Workers workers = (Workers) o;
        return Objects.equals(name, workers.name) && this.age == workers.age;
    }

/*    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Workers workers = (Workers) o;
        return age == workers.age && Objects.equals(name, workers.name);
    }*/

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

equals和hashCode示例2:重写2次

package com.SetExercise;

import org.junit.Test;

import java.util.Date;
import java.util.HashSet;
import java.util.Objects;

/**
 * @author 心向阳光的天域
 * @date 2022/10/7 15:19
 */
public class Employee02 {
    @Test
    public void getPerson() {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employ("小明", 10000.88d, new MyDate("1996", "01", "01")));
        // 姓名一样,出生年份不同
        hashSet.add(new Employ("小明", 10001.88d, new MyDate("1997", "01", "01")));
        // 出生年份和工资不同
        hashSet.add(new Employ("小明", 10001.88d, new MyDate("1998", "01", "01")));
        // 工资和第一个比不同(按照规则,这个应该不展示)
        hashSet.add(new Employ("小明", 10002.88d, new MyDate("1996", "01", "01")));

        // 重写了toString()方法,这里可以遍历一下,看看值
        System.out.println("size:" + hashSet.size());
        for (Object o : hashSet) {
            System.out.println(o);
        }
    }
}

class Employ {
    private String name;
    private double sal;
    private MyDate birthday;

    public Employ(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employ employ = (Employ) o;
        return Objects.equals(name, employ.name) && Objects.equals(birthday, employ.birthday);
    }

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

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

class MyDate {
    String year;
    String month;
    String day;

    public MyDate(String year, String month, String day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyDate myDate = (MyDate) o;
        return Objects.equals(year, myDate.year) && Objects.equals(month, myDate.month) && Objects.equals(day, myDate.day);
    }

    @Override
    public int hashCode() {
        return Objects.hash(year, month, day);
    }

    @Override
    public String toString() {
        return "MyDate{" +
                "year='" + year + '\'' +
                ", month='" + month + '\'' +
                ", day='" + day + '\'' +
                '}';
    }
}

equals和hashCode示例2:重写1次

package com.SetExercise;

import org.junit.Test;

import java.util.Date;
import java.util.HashSet;
import java.util.Objects;

/**
 * @author 心向阳光的天域
 * @date 2022/10/7 15:19
 */
public class Employee03 {
    @Test
    public void getPerson() {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employ("小明", 10000.88d, new MyDate("1996", "01", "01")));
        hashSet.add(new Employ("小明", 10001.88d, new MyDate("1997", "01", "01")));
        hashSet.add(new Employ("小明", 10001.88d, new MyDate("1998", "01", "01")));
        // 按照重复数据去重
        hashSet.add(new Employ("小明", 10002.88d, new MyDate("1996", "01", "01")));

        System.out.println("size:" + hashSet.size());
        for (Object o : hashSet) {
            System.out.println(o);
        }
    }
}

class Employ02 {
    private String name;
    private double sal;
    private MyDate02 birthday;

    public Employ02(String name, double sal, MyDate02 birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employ02 employ = (Employ02) o;
        return Objects.equals(name, employ.name)
                // 这里直接重写一次equals方法即可
                && Objects.equals(birthday.getYear(), employ.birthday.getYear())
                && Objects.equals(birthday.getMonth(), employ.birthday.getMonth())
                && Objects.equals(birthday.getDay(), employ.birthday.getDay());
    }

    @Override
    public int hashCode() {
        // 这里直接重写一次hashCode方法即可
        return Objects.hash(name, birthday.year, birthday.month, birthday.day);
    }

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

class MyDate02 {
    String year;
    String month;
    String day;

    public MyDate02(String year, String month, String day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }

    public String getDay() {
        return day;
    }

    public void setDay(String day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return "MyDate{" +
                "year='" + year + '\'' +
                ", month='" + month + '\'' +
                ", day='" + day + '\'' +
                '}';
    }
}

LinkedHashSet

LinkedHashSet的全面说明
(1)LinkedHashSet是HashSet的子类
(2)LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表+红黑树
(3)LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序图(图),这使得元素看起来是以插入顺序保存的。
(4)LinkedHashSet不允许添加重复元素

说明:

  1. 在LinkedHashSet中维护一个hash表和双向链表(LinkedHashSet 有head和tail)

  2. 每一个结点有before和after属性,这样可以形成双向链表

  3. 在添加一个元素时,先求hash值,再求索引,确定该元素在table的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加[原则和hashset一样])

    tail.next = newElement
    newElement.pre = tail
    tail = newElement;

  4. 这样的话,我们遍历LinkedHashSet 也能确保插入顺序和遍历顺序一致

equals和hashCode重写

package com.SetExercise;

import org.junit.Test;

import java.util.LinkedHashSet;
import java.util.Objects;

/**
 * @author wty
 * @date 2022/10/8 19:57
 * 如果name和price一样就认为是一样的元素
 */
public class LinkedHashSetExercise01 {

    @Test
    public void getHashSet() {
        LinkedHashSet set = new LinkedHashSet();
        set.add(new Car("奥迪", 1000d));
        set.add(new Car("奥迪", 30000d));
        set.add(new Car("法拉利", 100000d));
        set.add(new Car("保时捷", 7000000d));
        set.add(new Car("奥迪", 1000d));


        for (Object o : set) {
            System.out.println(o);
        }
    }
}

class Car {
    private String name;
    private double price;

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

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

    // 重写equals和hash方法
    @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接口实现类的特点

(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
(8)Map存放数据的key-value示意图,一对key-value 是放在一个Node中的,又因为Node实现了Entry接口,有些书上也说一对key-value就是一个Entry(如图)

package com.Map;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/8 22:45
 */
public class MapExercise {
    @Test
    public void getExercise() {
        // Map接口具有的特点
        // 常用String类作为Map的key
        Map hashMap = new HashMap();
        hashMap.put("1", "Jack");
        hashMap.put("2", 10);
        hashMap.put("3", "贾斯汀比伯");
        hashMap.put("4", "迈克尔杰克逊");
        hashMap.put("5", "贾斯汀比伯");
        hashMap.put("6", "Alice");
        hashMap.put("7", "VERTGA");
        hashMap.put("8", "LAM");
        hashMap.put("9", "GIN");
        hashMap.put("10", "TIO");
        hashMap.put("11", "AIO");
        hashMap.put("12", "Tony");
        hashMap.put("13", "Joy");
        hashMap.put("1", "Rose"); // 替换机制:当有相同key值时。就替换
        hashMap.put(null, null);
        hashMap.put(null, null); // Map的key可以为null,value也可以为null,注意key为null,只能有一个,value为null可以多个
        hashMap.put("17", null);
        hashMap.put(null, 181); // 替换
        hashMap.put(1, "Jack"); // key可以用别的类型

        System.out.println(hashMap);
        System.out.println("get(1):" + hashMap.get(1));


    }
}

entrySet()获取entrySet,entrySet是一个Set接口,里面存放的是Entry对象,Entry对象里面存放的是key的引用和value的引用

Map的常用方法

(1)put:添加
(2)remove:根据键删除映射关系
(3)get:根据键获取值
(4)size:获取元素个数
(5)isEmpty:判断个数是否为0
(6)clear:清除
(7)containsKey:查找键是否存在

package com.Map;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/9 9:02
 */
public class MapUse {
    @Test
    public void mapUse() {
        /**
         * (1)put:添加
         * (2)remove:根据键删除映射关系
         * (3)get:根据键获取值
         * (4)size:获取元素个数
         * (5)isEmpty:判断个数是否为0
         * (6)clear:清除
         * (7)containsKey:查找键是否存在
         */

        Map map = new HashMap();
        map.put("1", "Book");
        map.put("邓超", "孙俪");
        map.put("马蓉", "王宝强");
        map.put("马蓉", "宋喆");

        System.out.println(map);

        map.remove("1");
        System.out.println(map);

        System.out.println(map.get("邓超"));

        System.out.println("size:" + map.size());

        System.out.println("是否为空:" + map.isEmpty());

        System.out.println("有没有马蓉: " + map.containsKey("马蓉"));

        map.clear();
        System.out.println("clean之后" + map);


    }
}

Map接口遍历方法

Map遍历的示意图(比List,和Set复杂一点,但是基本原理一样)
(1)containsKey:查找键是否存在
(2)keySet:获取所有的键
(3)entrySet:获取所有关系
(4)values:获取所有的值

package com.Map;
	
	import org.junit.Test;
	
	import java.util.*;
	
	/**
	 * @author wty
	 * @date 2022/10/9 9:15
	 */
	public class MapBl {
	    @Test
	    public void Mapbl() {
	        Map map = new HashMap();
	        map.put("1", "Jack");
	        map.put("上单", "老夫子");
	        map.put("中单", "诸葛亮");
	        map.put("射手", "后裔");
	        System.out.println(map);
	
	        // 遍历(自己想的)
	        System.out.println("----增强for循环----");
	        Set set = map.entrySet();
	        for (Object o : set) {
	            System.out.println(o);
	        }
	
	        // 遍历(自己想的)
	        System.out.println("----迭代器----");
	        Iterator iterator = map.entrySet().iterator();
	        while (iterator.hasNext()) {
	            Object next = iterator.next();
	            System.out.println(next);
	        }
	
	
	        // 韩老师讲的
	        // 1. 先取出所有的key,通过key找到对应的value
	        System.out.println("----map.keySet()----");
	        Set keyset = map.keySet();
	        for (Object o : keyset) {
	            // 向下转型
	            System.out.println("key = " + o + "   value = " + map.get(o));
	
	        }
	
	        // 2.通过迭代器
	        System.out.println("----map.keySet()的迭代器----");
	        Iterator iterator1 = keyset.iterator();
	        while (iterator1.hasNext()) {
	            Object next = iterator1.next();
	            System.out.println("key = " + next + "   value = " + map.get(next));
	        }
	
	        // 3.只是把所有的values取出
	        System.out.println("----map.values()----");
	        Collection values = map.values();
	        for (Object value : values) {
	            System.out.println("value = " + value);
	        }
	
	        System.out.println("----map.values()迭代器----");
	        Iterator iterator2 = values.iterator();
	        while (iterator2.hasNext()) {
	            Object next = iterator2.next();
	            System.out.println("value = " + next);
	        }
	
	        // 3.通过EntrySet
	        // 增强for循环
	        System.out.println("----map.entrySet()增强for循环----");
	        Set entryset = map.entrySet();
	        for (Object o : entryset) {
	            Map.Entry entry = (Map.Entry) o;
	            System.out.println("key = " + entry.getKey() + "  value = " + entry.getValue());
	
	        }
	
	
	        // 通过迭代器
	        System.out.println("----entrySet迭代器----");
	        Set entrySet = map.entrySet();
	        Iterator iterator3 = entrySet.iterator();
	        while (iterator3.hasNext()) {
	            Object next = iterator3.next();
	            //System.out.println(next.getClass()); // HashMap$Node
	
	            Map.Entry entry = (Map.Entry) next;
	            System.out.println("key = " + entry.getKey() + "  value = " + entry.getValue());
	        }
	    }
	}

课后练习

韩顺平 Java集合 自学笔记(Java30天基础)_第10张图片

package com.Map;

import org.junit.Test;

import java.util.*;

/**
 * @author wty
 * @date 2022/10/9 12:41
 */
public class AfterClassExercise {
    @Test
    public void showWorkers() {
        /*HashSet hashSet = new HashSet();
        hashSet.add(new Workers("王晓亮", 15000.5, "no.1"));
        hashSet.add(new Workers("钟飞扬", 16060.5, "no.2"));
        hashSet.add(new Workers("潘长江", 18060.5, "no.3"));
        hashSet.add(new Workers("小悦悦", 27060.5, "no.4"));
        System.out.println(hashSet);

        for (Object o : hashSet) {
            Map.Entry entry = (Map.Entry) o;
            entry.getKey();
        }*/


        HashMap hashMap = new HashMap();
        hashMap.put("no.1", new Workers("王晓亮", 15000.5, "no.1"));
        hashMap.put("no.2", new Workers("钟飞扬", 16060.5, "no.2"));
        hashMap.put("no.3", new Workers("潘长江", 18060.5, "no.3"));
        hashMap.put("no.4", new Workers("小悦悦", 27060.5, "no.4"));
        hashMap.put("no.5", "Jack");

        // 显示工资大于18000的人
        System.out.println("-----------------keySet()------------------");
        Set set = hashMap.keySet();
        for (Object o : set) { // String
            //System.out.println(o.getClass());
            if (hashMap.get(o) instanceof Workers) {
                Workers workers = (Workers) hashMap.get(o); // hashMap.get(o) 是对象Workers
                if (workers.getSal() > 18000) {
                    System.out.println("key = " + o + "   value = " + hashMap.get(o));
                }
            } else {
                System.out.println("key = " + o + "   value = " + hashMap.get(o));
            }
        }

        // 迭代器
        System.out.println("-----------------keySet()迭代器------------------");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            if (hashMap.get(next) instanceof Workers) {
                Workers workers = (Workers) hashMap.get(next);
                if (workers.getSal() > 18000) {
                    System.out.println("key = " + next + "   value = " + hashMap.get(next));
                }
            } else {
                System.out.println("key = " + next + "   value = " + hashMap.get(next));
            }

        }

        // 使用entrySet()方法
        System.out.println("-----------entrySet()增强for循环-----------");
        Set set1 = hashMap.entrySet();
        for (Object o : set1) {
            Map.Entry entry = (Map.Entry) o;
            if (entry.getValue() instanceof Workers) {
                Workers workers = (Workers) entry.getValue();

                if (workers.getSal() > 18000) {
                    System.out.println("key = " + entry.getKey() + "   value = " + entry.getValue());
                }
            } else {
                System.out.println("key = " + entry.getKey() + "   value = " + entry.getValue());
            }
        }

    }
}


class Workers {
    private String name;
    private double sal;
    String id;

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

    public double getSal() {
        return sal;
    }

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

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

}

HashMap小结

  1. Map接口的常用实现类:HashMap、Hashtable和Properties
  2. HashMap是Map接口使用频率最高的实现类
  3. HashMap是以key-value 对的方式来存储数据(HashMap$Node类型)
  4. key不能重复,但是值可以重复,允许使用null值和null键(null键只能有1个)
  5. 如果添加相同的key,则会覆盖原来的key-val,等同于修改(key不会替换,val会替换)
  6. 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的。
  7. HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

HashMap底层机制以及源码剖析

(1)HashMap底层维护了Node类型的数组table,默认为null
(2)当创建对象时,将加载因子(loadFactor)初始化为0.75
(3)当添加key-value时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素,则直接添加。如果该处索引有元素,则继续判断该元素的key是否和准备加入的key相等,如果相等,则直接替换成新的val,如果不相等,需要判断是树结构还是链表结构,做出相应的处理。如果添加时发现容量不够,则需要扩容。
(4)第1次添加,则需要扩容table容量为16,临界值(threshold)为12
(5)以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,即24,以此类推。
(6)在Java8中,如果一条链表的元素个数超过了TREEIFY_THRESHOLD(默认是8),并且table的大小>= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

模拟HashMap触发扩容、树化情况

package com.Map;

import org.junit.Test;

import java.util.*;

/**
 * @author wty
 * @date 2022/10/9 16:41
 */
public class HashMapSource {
    @Test
    public void getSource() {
        HashMap hashMap = new HashMap();
        //HashSet hashSet = new HashSet();
        //LinkedHashSet linkedHashSet = new LinkedHashSet();
        hashMap.put(new Cat("小红", 1) , "no1.Jack");
        hashMap.put(new Cat("小红", 2) , "no2.Jack");
        hashMap.put(new Cat("小红", 3) , "no3.Jack");
        hashMap.put(new Cat("小红", 4) , "no4.Jack");
        hashMap.put(new Cat("小红" ,5) , "no5.Jack");
        hashMap.put(new Cat("小红", 6) , "no6.Jack");
        hashMap.put(new Cat("小红", 7) , "no7.Jack");
        hashMap.put(new Cat("小红", 8) , "no8.Jack");
        /**
         * // 从第二次put之后才会进这里,并且第二次循环时 var12 0  第二次循环结束 var12 1 -- 即第三次循环开始 var12 1
         *    所以var12比put的次数少2,一直到put第9的时候,var12 >= 7才会满足
         *                 while(true) {
         *                     if ((var10 = ((HashMap.Node)var7).next) == null) {
         *                         ((HashMap.Node)var7).next = this.newNode(var1, var2, var3, (HashMap.Node)null);
         *                         if (var12 >= 7) {
         *                             this.treeifyBin(var6, var1);
         *                         }
         *                         break;
         *                     }
         *
         *                     if (((HashMap.Node)var10).hash == var1 && ((var11 = ((HashMap.Node)var10).key) == var2 || var2 != null && var2.equals(var11))) {
         *                         break;
         *                     }
         *
         *                     var7 = var10;
         *                     ++var12;
         *                 }
         */
        hashMap.put(new Cat("小红", 9) , "no9.Jack");
        hashMap.put(new Cat("小红", 10) , "no10.Jack");
        hashMap.put(new Cat("小红", 11) , "no11.Jack");
        hashMap.put(new Cat("小红", 12) , "no12.Jack");
        /**
         * if (++this.size > this.threshold) { 所以是第13次put的时候扩容 16 → 32
         *             this.resize();
         *         }
         */
        hashMap.put(new Cat("小红", 13) , "no13.Jack"); //
        hashMap.put(new Cat("小红", 14) , "no14.Jack");



        hashMap.put(new Cat("小蓝", 9) , "no9.Jack"); // 扩容table 32
        hashMap.put(new Cat("小蓝", 10) , "no10.Jack"); // 扩容table 64
        hashMap.put(new Cat("小蓝", 11) , "no11.Jack"); // 将链表转换成红黑树
        //hashMap.put("11", "no111.Jack");
        //hashMap.put("12", "no12.Jack");
        //hashMap.put("13", "no13.Jack"); // 超过12才扩容
/*        hashMap.remove(new Cat("小蓝", 11));
        hashMap.remove(new Cat("小蓝", 10));
        hashMap.remove(new Cat("小蓝", 9));
        hashMap.remove(new Cat("小红", 8));
        hashMap.remove(new Cat("小红", 7));
        hashMap.remove(new Cat("小红", 6));
        hashMap.remove(new Cat("小红", 5));
        hashMap.remove(new Cat("小红", 4)); // 执行完之后剪枝
        hashMap.remove(new Cat("小红", 3));
        hashMap.remove(new Cat("小红", 3));*/

        Set set = hashMap.keySet();
        for (Object o : set) {
            System.out.println("key = " + o + " value = " + hashMap.get(o));
        }
        System.out.println(hashMap);
    }
}

class Cat {
    private  String name;
    private  int age;

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

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

    @Override
    public int hashCode() {
        return Objects.hash(100);
    }
}

Map接口实现类-Hashtable

(1)存放的元素是键值对:即K-V
(2)hashtable的键和值都不能为null,否则会抛出NullPointerException
(3)hashTable使用方法基本上和HashMap一样
(4)hashTable是线程安全的(synchronized),hashMap是线程不安全的
(5)实现Map接口

注意:

  1. 底层有数组 Hashtable$Entry[] 初始化大小为11
  2. 临界值 threshold = 11 * 0.75 ≈ 8
  3. 扩容:按照自己的扩容机制来进行
  4. 执行方法 addEntry(hash, key, value, index); 添加键值对,封装到Entry

Hashtable和HashMap对比

名称 版本 线程安全(同步) 效率 允许null键null值
Hashtable 1.2 不安全 可以
HashMap 1.0 安全 较低 不可以

Properties

基本介绍

  1. Properties类继承自Hashtable类并且实现了Map接口,也是一种键值对的形式来保存数据。
  2. 它的使用特点和Hashtable类似。
  3. Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改。
  4. 说明:工作后xxx.properties文件通常作为配置文件,这个知识点在IO流举例,有兴趣可先看文章。

配置文件不会显示乱码,统一调整为UTF-8

PropertiesEx.java

	package com.Map.Properties;
	
	import org.junit.Test;
	
	import java.io.*;
	import java.util.Iterator;
	import java.util.Map;
	import java.util.Properties;
	import java.util.Set;
	
	/**
	 * @author wty
	 * @date 2022/10/9 23:49
	 */
	public class PropertiesEx {
	    @Test
	    public void propertiesEx() {
	        Properties properties = new Properties();
	
	        String path = "src/com/Map/File/res.properties";
	
	        BufferedReader bufferedReader = null;
	        BufferedWriter bufferedWriter = null;
	        try {
	            bufferedReader = new BufferedReader(new FileReader(path));
	            properties.load(bufferedReader);
	            Set<Map.Entry<Object, Object>> entries = properties.entrySet();
	            Iterator<Map.Entry<Object, Object>> iterator = entries.iterator();
	            while (iterator.hasNext()) {
	                Map.Entry<Object, Object> next = iterator.next();
	                System.out.println("key = " + next.getKey() + " value = " + next.getValue());
	            }
	
	            // 写入
	            bufferedWriter = new BufferedWriter(new FileWriter(path));
	            properties.setProperty("signature", "rose");
	            properties.setProperty("signature", "厉害");
	            properties.store(bufferedWriter, "This is my destney哈哈");
	
	
	        } catch (IOException e) {
	            e.printStackTrace();
	        } finally {
	            try {
	                bufferedReader.close();
	                bufferedWriter.close();
	
	            } catch (IOException e) {
	                e.printStackTrace();
	            }
	        }
	    }
	}

res.properties

name=root
key=value
pass=liu

基本用法

package com.Map.Properties;

import org.junit.Test;

import java.util.Properties;

/**
 * @author wty
 * @date 2022/10/10 9:46
 */
public class PropertiesExercise {
    @Test
    public void getEx() {
        Properties properties = new Properties();
        properties.put("no.1", "Jack");
        properties.put("no.2", "Jone");
        // 有相同的key,value会被替换
        properties.put("no.2", "Joy");
        //properties.put(null,null); // java.lang.NullPointerException
        // 键不能为空
        //properties.put(null,"1"); // java.lang.NullPointerException
        // 值不能为空
        //properties.put("no.3",null); // java.lang.NullPointerException

        properties.put("no.3", "Rose");


        System.out.println(properties);

        // 通过key获取对应的值
        System.out.println("no.2:  " + properties.get("no.2"));

        properties.remove("no.3");
        System.out.println("删除no.3之后");
        System.out.println(properties);


        // 修改:
        properties.setProperty("no.2", "Alice");
        System.out.println("setProperty修改no.2之后");
        System.out.println(properties);

        properties.put("no.2", "Rice");
        System.out.println("putno.2之后");
        System.out.println(properties);

        // 查找
        System.out.println("getProperty no.1之后");
        System.out.println(properties.getProperty("no.1"));
    }
}

集合选型

在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行选择,分析如下:

(1)先判断存储类型(一组对象(单列)或者键值对(双列))  
(2)一组对象: Collection接口  
   允许重复:List  
            增删多:LinkedList(底层是双向链表)  
            查改多:ArrayList(底层维护Object类型的可变数组)  
  不允许重复:Set
            无序:HashSet底层是HashMap,维护一个Hash表(数组+链表+红黑树)  
			排序:TreeSet  
            插入和取出顺序一样: LinkedHashSet(继承自LinkedHashMap),维护数组+双向链表  
(3)键值对:Map
         键无序:HashMap(底层是:哈希表:数组+链表+红黑树)  
		 键有序:TreeMap  
         键插入和取出顺序一致:LinkedHashMap(继承自HashMap)  
 		 读取文件: Properties  

TreeSet

TreeSet含Comparator构造器

package com.SetExercise;

import org.junit.Test;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author wty
 * @date 2022/10/10 10:20
 */

public class TreeSetExercise {
    @Test
    @SuppressWarnings({"all"})
    public void getTreeSet() {
        // 当使用无参构造器创建TreeSet的时候是无序的
        TreeSet treeSet = new TreeSet();
        // 添加数据
        treeSet.add("Derrick");
        treeSet.add("Rose");
        treeSet.add("Jam");
        treeSet.add("Timmy");
        treeSet.add("Tom");

        System.out.println(treeSet);


        System.out.println("---字符串按照首字母顺序比较---");
        // 添加的元素按照字符串大小来排序
        // 可以传入一个比较器(匿名内部类),并指定规则
        TreeSet treeSet1 = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o, Object t1) {
                return ((String) o).compareTo((String) t1);
            }
        });
        treeSet1.add("Derrick");
        treeSet1.add("Rose");
        treeSet1.add("Jam");
        treeSet1.add("Timmy");
        treeSet1.add("Tom");

        System.out.println(treeSet1);
        // 源码解读
        /**
         *     public TreeMap(Comparator var1) {
         *         this.comparator = var1; 把new Comparator() 给到TreeMap的comparator属性
         *     }
         */

        System.out.println("---字符串长度大小比较---");
        TreeSet treeSet2 = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o, Object t1) {
                String str_a = (String) o;
                String str_t1 = (String) t1;
                int a = ((String) o).length();
                int b = ((String) t1).length();
                int result = a - b;
                return result = result == 0 ? str_a.compareTo(str_t1) : result;
            }
        });
        treeSet2.add("Derrick");
        treeSet2.add("Amy");
        treeSet2.add("Rose");
        treeSet2.add("Jam"); // 相同长度加不进去
        treeSet2.add("Timmy");
        treeSet2.add("Tom");// 相同长度加不进去


        System.out.println(treeSet2);


    }
}

TreeMap

package com.Map;

import org.junit.Test;

import java.util.Comparator;
import java.util.TreeMap;

/**
 * @author wty
 * @date 2022/10/10 12:33
 */
public class TreeMapExercise {
    @Test
    public void getTreeMap() {
        // 无参数,无序取出
        TreeMap treeMap = new TreeMap();
        treeMap.put("1", "Jack");
        treeMap.put("no2", "Tom");
        treeMap.put("李小璐", "PGONE");
        treeMap.put("smith", "史密斯");

        System.out.println(treeMap);

        // 按照key字符串首字母倒叙排序
        TreeMap treeMap2 = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o2).compareTo((String) o1);
            }
        });
        System.out.println("按照key字符串首字母倒叙排序");
        treeMap2.put("1", "Jack");
        treeMap2.put("no2", "Tom");
        treeMap2.put("李小璐", "PGONE");
        treeMap2.put("smith", "史密斯");
        treeMap2.put("alice", "漫游记");
        System.out.println(treeMap2);

        // 按照key字符串长度排序,相同长度按首字母倒叙排序
        TreeMap treeMap3 = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                String str_o1 = (String) o1;
                String str_o2 = (String) o2;

                int a = str_o1.length();
                int b = str_o2.length();

                int result = a == b ? str_o1.compareTo(str_o2) : a - b;

                return result;
            }
        });
        System.out.println("按照key字符串长度排序,相同长度按首字母顺叙排序");
        treeMap3.put("1", "Jack");
        treeMap3.put("no2", "Tom");
        treeMap3.put("李小璐", "PGONE");
        treeMap3.put("smith", "史密斯");
        treeMap3.put("alice", "漫游记");
        treeMap3.put("tonny", "理发师");
        System.out.println(treeMap3);
    }
}

Collections工具类

Collections工具类介绍
(1)Collections是一个操作Set、List和Map等集合的工具类
(2)Collections中提供了一系列静态的方法对集合元素进行排序、查询和修改操作

排序操作(均为static方法)

(1)reverse(List):反转List中元素的顺序
(2)shuffle(List):对List集合元素进行随机排序
(3)sort(List):根据元素的自然顺序对指定List集合元素按升序排序
(4)sort(List,Comparator):根据指定的Comparator产生的顺序对List集合进行排序
(5)swap(List,int,int):将指定list集合中的i处元素和j处元素进行交换

package com.CollectionsUse;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

/**
 * @author wty
 * @date 2022/10/10 14:57
 */
public class CollectionsUse {
    @Test
    public void getUse() {
        HashMap hashMap = new HashMap();
        hashMap.put("Jack", "Rose");
        hashMap.put("no.1", "Tony");
        hashMap.put("no.2", "Jancy");
        hashMap.put("This", "is my destney");

        /**
         * (1)reverse(List):反转List中元素的顺序
         * (2)shuffle(List):对List集合元素进行随机排序
         * (3)sort(List):根据元素的自然顺序对指定List集合元素按升序排序
         * (4)sort(List,Comparator):根据指定的Comparator产生的顺序对List集合进行排序
         * (5)swap(List,int,int):将指定list集合中的i处元素和j处元素进行交换
         */
        System.out.println(hashMap);


        ArrayList arrayList = new ArrayList();
        arrayList.add("Derrick");
        arrayList.add("Rose");
        arrayList.add("no.1");
        arrayList.add("2");
        arrayList.add("周润发");
        arrayList.add("周杰伦");
        arrayList.add("洪辰");
        System.out.println("----正常-----");
        System.out.println(arrayList);

        Collections.reverse(arrayList); // (1)reverse(List):反转List中元素的顺序
        System.out.println("----倒叙----");
        System.out.println(arrayList);

        System.out.println("----随机顺序----");
        Collections.shuffle(arrayList); // (2)shuffle(List):对List集合元素进行随机排序
        System.out.println(arrayList);


        System.out.println("----再次随机顺序----");
        Collections.shuffle(arrayList);
        System.out.println(arrayList);

        System.out.println("----自然排序----"); // 根据元素的自然顺序对指定List集合元素按升序排序
        Collections.sort(arrayList);
        System.out.println(arrayList);


        // sort(List,Comparator):根据指定的Comparator产生的顺序对List集合进行排序
        System.out.println("----自然排序Comparator:按照字符串长度大小排序----");
        Collections.sort(arrayList, new Comparator() {

            @Override
            public int compare(Object o1, Object o2) {

                if (o1 instanceof String && o2 instanceof String) {

                    String str_o1 = (String) o1;
                    String str_o2 = (String) o2;

                    int a = str_o1.length();
                    int b = str_o2.length();

                    int result = a == b ? str_o1.compareTo(str_o2) : a - b;
                    return result;
                } else {
                    return 0;
                }
            }
        });
        System.out.println(arrayList);

        // (5)swap(List,int,int):将指定list集合中的i处元素和j处元素进行交换
        System.out.println("----交换第一个和第三个元素----");
        Collections.swap(arrayList, 0, 2);
        System.out.println(arrayList);


    }
}

查找和替换

(1)Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
(2)Object max(Collection, Comparator):根据Compartor指定的顺序,返回给定集合中的最大元素
(3)Object min(Collection)
(4)Object min(Collection, Object)
(5)int frequency(Collection, Object):返回指定集合中指定元素的出现次数
(6)void copy(List dest, List src):将src中的内容复制到dest中
(7)boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值

@Test
    public void getUseCollections() {

        /**
         * (1)reverse(List):反转List中元素的顺序
         * (2)shuffle(List):对List集合元素进行随机排序
         * (3)sort(List):根据元素的自然顺序对指定List集合元素按升序排序
         * (4)sort(List,Comparator):根据指定的Comparator产生的顺序对List集合进行排序
         * (5)swap(List,int,int):将指定list集合中的i处元素和j处元素进行交换
         */


        ArrayList arrayList = new ArrayList();
        arrayList.add("Derrick");
        arrayList.add("Rose");
        arrayList.add("no.1");
        arrayList.add("2");
        arrayList.add("周润发");
        arrayList.add("周杰伦");
        arrayList.add("洪辰");
        arrayList.add("Rose");
        System.out.println("----正常-----");
        System.out.println(arrayList);

        /**
         * (1)Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
         * (2)Object max(Collection, Comparator):根据Compartor指定的顺序,返回给定集合中的最大元素
         * (3)Object min(Collection)
         * (4)Object min(Collection, Object)
         * (5)int frequency(Collection, Object):返回指定集合中指定元素的出现次数
         * (6)void copy(List dest, List src):将src中的内容复制到dest中
         * (7)boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值
         */

        // (1)Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
        System.out.println("Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素");
        System.out.println(Collections.max(arrayList));

        // Object max(Collection, Comparator):根据Compartor指定的顺序,返回给定集合中的最大元素
        System.out.println("Object max(Collection, Comparator):根据Compartor指定的顺序,返回给定集合中的最大元素  ");
        System.out.println(Collections.max(arrayList, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {

                if (o1 instanceof String && o2 instanceof String) {

                    String str_o1 = (String) o1;
                    String str_o2 = (String) o2;

                    int a = str_o1.length();
                    int b = str_o2.length();

                    int result = a == b ? str_o1.compareTo(str_o2) : a - b;
                    return result;
                } else {
                    return 0;
                }
            }
        }));


        // (3)Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素
        System.out.println("Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素");
        System.out.println(Collections.min(arrayList));


        // Object max(Collection, Comparator):根据Compartor指定的顺序,返回给定集合中的最大元素
        System.out.println("Object min(Collection, Comparator):根据Compartor指定的顺序,返回给定集合中的最小元素  ");
        System.out.println(Collections.min(arrayList, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {

                if (o1 instanceof String && o2 instanceof String) {

                    String str_o1 = (String) o1;
                    String str_o2 = (String) o2;

                    int a = str_o1.length();
                    int b = str_o2.length();

                    int result = a == b ? str_o1.compareTo(str_o2) : a - b;
                    return result;
                } else {
                    return 0;
                }
            }
        }));

        // int frequency(Collection, Object):返回指定集合中指定元素的出现次数
        System.out.println("int frequency(Collection, Object):返回指定集合中指定元素的出现次数 ");
        System.out.println(Collections.frequency(arrayList, "Rose"));


        // void copy(List dest, List src):将src中的内容复制到dest中
        // 拷贝要注意 ,拷贝后的集合dest的元素个数要>=被拷贝集合arrayList
        // 一般情况在初始化dest指定大小和arrayList相同
        //ArrayList dest = new ArrayList(); // java.lang.IndexOutOfBoundsException
        ArrayList dest = new ArrayList();
        for (int i = 0; i < arrayList.size(); i++) {
            dest.add(i);
        }
        dest.add("Copy");
        dest.add("Paste");
        Collections.copy(dest, arrayList);
        System.out.println("dest集合元素:");
        System.out.println(dest);

        ArrayList arrayList1 = new ArrayList(10); // 指的是容量(达到后下次扩容成当前的1.5倍)
        System.out.println("arrayList1.size(): " + arrayList1.size());

        //boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值
        System.out.println("boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值  ");
        Collections.replaceAll(dest, "周润发", "金喜善"); // 如果有周润发就替换成金喜善
        System.out.println(dest);

    }

课后作业

课后作业1:

package com.HomeWork;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * @author wty
 * @date 2022/10/10 16:06
 */
public class HomeWork01 {
    @Test
    public void HomeWork() {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new News("新闻一:新冠确诊病例超过千万,数以万计印度教徒赶赴恒河"));
        arrayList.add(new News("新闻二:男子突然想起2个月前钓的鱼还在网兜"));
        System.out.println("----倒序遍历----");
        Collections.reverse(arrayList);
        for (Object o : arrayList) {
            // 先实例化对象
            News news = (News) o;

            if (news.getTitle().length() > 15) {
                System.out.println(news.getTitle().substring(0, 15) + "…………");
            } else {
                System.out.println(news.getTitle());
            }
        }
    }

    @Test
    public void HomeWork01_Teacher() {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new News("新闻一:新冠确诊病例超过千万,数以万计印度教徒赶赴恒河"));
        arrayList.add(new News("新闻二:男子突然想起2个月前钓的鱼还在网兜"));
        System.out.println("----倒序遍历----");

        for (int i = arrayList.size() - 1; i >= 0; i--) {
            News news = (News) arrayList.get(i);
            System.out.println(substrTitle(news.getTitle()));
        }
    }

    public String substrTitle(String title) {
        if (null == title || "".equals(title)) {
            return "";
        }

        if (title.length() > 15) {
            return title.substring(0, 15) + "…………";
        } else {
            return title;
        }
    }
}

class News {
    private String title;
    private String text;

    public String getTitle() {
        return title;
    }

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

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

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

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

课后习题2

package com.HomeWork;

import org.junit.Test;

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

/**
 * @author wty
 * @date 2022/10/10 16:38
 */
public class HomeWork02 {
    @Test
    public void getHomeWork02() {
        List list = new ArrayList();
        Car car1 = new Car("宝马", 400000);
        Car car2 = new Car("宾利", 5000000);
        Car car3 = new Car("劳斯莱斯", 60000000);
        Car car4 = new Car("法拉利", 70000000);
        list.add(car1);
        list.add(car2);
        System.out.println(list);

        list.remove(car1);
        System.out.println(list);

        System.out.println(list.contains(car2));

        System.out.println(list.size());
        System.out.println(list.isEmpty());
        list.clear();
        System.out.println(list);

        List list2 = new ArrayList();
        list2.add(car1);
        list2.add(car2);
        list2.add(car3);
        list2.add(car4);
        list.addAll(list2);
        System.out.println("----list.addAll(list2)----");
        System.out.println(list);


        System.out.println(list2.containsAll(list));
        list2.removeAll(list);
        System.out.println(list2);

        System.out.println("list增强for循环");

        for (Object o : list) {
            System.out.println(o);
        }

        System.out.println("list迭代器");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }


    }
}

class Car {
    private String name;
    private double price;

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

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

课后习题3

package com.HomeWork;

import org.junit.Test;

import java.util.*;

/**
 * @author wty
 * @date 2022/10/10 16:52
 */
public class HomeWork03 {
    @Test
    public void getHomeWork03() {
        Map map = new HashMap();
        map.put("1", new Worker("jack", 650));
        map.put("2", new Worker("tom", 1200));
        map.put("3", new Worker("smith", 2900));

        System.out.println("正常情况");
        Set set = map.keySet();
        for (Object o : set) {
            Worker worker = (Worker) map.get(o);
            System.out.println(worker);
        }

        // jack更改为2600元
        System.out.println("----更改工资和加薪后----");
        map.put("1", new Worker("jack", 2600));
        System.out.println(map);
        // 为所有员工加薪100元
        Set set1 = map.entrySet();
        Iterator iterator = set1.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();

            Map.Entry entry = (Map.Entry) next;

            Worker worker = (Worker) entry.getValue();

            // 加薪
            worker.setSal(worker.getSal() + 100);
            //System.out.println(worker.getSal() + 100);

            System.out.println(worker);

        }

        System.out.println("----遍历工资----");
        // 把工资遍历出来
        Collection values = map.values();
        for (Object value : values) {
            Worker worker = (Worker) value;
            System.out.println(worker.getSal());
        }


    }
}

class Worker {
    private String name;
    private double sal;

    public Worker(String name, double sal) {
        this.name = name;
        this.sal = sal;
    }

    @Override
    public String toString() {
        return name + "————" + sal + "元";
    }

    public double getSal() {
        return sal;
    }

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

简答题

试分析HashSet和TreeSet分别是如何实现去重的

(1)HashSet的去重机制:hashCode() + equals(),底层先通过存入对象,进行运算得到一个hash值,通过hash值得到对应的索引,如果发现table索引所在的位置,没有数据,就直接存放,如果有数据,就进行equals比较[遍历比较],如果比较后不相同就加入,否则就不加入。
(2)TreeSet的去重机制:如果你传入了一个Comparator匿名对象,就使用实现的compare去重,如果方法返回0,就认为是相同的元素/数据,就不添加,如果你没有传入一个Comparator匿名对象,则以你添加的对象实现的Comparator接口的compareTo去重。

课后作业5:

package com.HomeWork;

import org.junit.Test;

import java.util.TreeMap;
import java.util.TreeSet;

/**
 * @author wty
 * @date 2022/10/10 17:47
 */
public class HomeWork05 {
    @Test
    public void getHomeWorker05() {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Person()); // java.lang.ClassCastException 报错
        // 错误原因:treeSet在add时候会执行
        /**
         *     final int compare(Object var1, Object var2) {
         *         return this.comparator == null ? ((Comparable)var1).compareTo(var2) : this.comparator.compare(var1, var2);
         *     }
         *
         *     会把加入的元素var1 转换成(Comparable) 对象,所以Person必须实现Comparable接口才行
         */
    }
}

class Person implements Comparable { // 实现之后再添加就不会报错了
    /**
     *TreeSet的去重机制:如果你传入了一个Comparator匿名对象,就使用实现的compare去重,如果方法返回  	0,就认为是相同的元素/数据,就不添加,如果你没有传入一个Comparator匿名对象,则以你添加的对象实现的Comparator接口的compareTo去重。
     *     final int compare(Object var1, Object var2) {
     *         return this.comparator == null ? ((Comparable)var1).compareTo(var2) : this.comparator.compare(var1, var2);
     *     }
     * @param o
     * @return
     */
    @Override
    public int compareTo(Object o) {
        return 0;
    }
}

课后作业7

Vector和ArrayList比较

           底层结构      版本   线程安全(同步)效率    扩容倍数
ArrayList  可变数组      1.2    线程不安全,效率高   无参第一次扩容至10,从第二次开始按照1.5倍扩容

Vector     可变数组      1.0    线程安全,效率低     无参第一次扩容至10,从第二次开始按照2倍扩容
名称 底层结构 版本 线程安全(同步) 效率 扩容倍数
ArrayList 可变数组 1.2 线程不安全 无参第一次扩容至10,从第二次开始按照1.5倍扩容
Vector 可变数组 1.0 线程安全 无参第一次扩容至10,从第二次开始按照2倍扩容

你可能感兴趣的:(韩顺平,java,junit,开发语言)