韩顺平 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 {@Testpublic 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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}

集合的好处

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

集合类图

Collection 接口图

Map接口图

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);// 删除第一个元素hellolist.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本身并不存放对象

迭代器的执行原理

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()) { // 判断是否还有数据// 返回下一个元素,类型是ObjectObject 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;}@Overridepublic 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 {@Testpublic 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;}@Overridepublic 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 {@Testpublic 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;}@Overridepublic 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 {@Testpublic 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 {@Testpublic 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 {@Testpublic 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));}}@Testpublic 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

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

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 {@Testpublic 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;}@Overridepublic 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比较

LinkedList底层结构

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

LinkedList的底层操作机制

(1)LinkedList底层维护了一个双向链表
(2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点
(3)每个节点(Node对象),里面又维护了prev,next,item三个属性,其中通过prev指向前一个,通过next指向后一个节点 ,最终实现双向链表。
(4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高

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

package com.ListExercise;import org.junit.Test;/*** @author wty* @date 2022/10/6 14:45* 模拟一个双向链表*/
public class LinkedListExercise02 {@Testpublic 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;}@Overridepublic 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 {@Testpublic void linkedListCRUD() {LinkedList list = new LinkedList();list.add(100);list.add(200);list.add(300);System.out.println(list);// 修改,把200更改成400System.out.println(list.set(1, 400)); // 200// 删除400System.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 {@Testpublic 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 {@Testpublic  void getHashSetStr(){// 模拟一个HashSet的底层(其实就是HashMap)// 创建一个Node数组,有些人称为tableNode[] 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)就进行树化(红黑树)

课堂练习

课后练习

equals和hashCode示例1:

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 {@Testpublic 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;}@Overridepublic String toString() {return "Workers{" +"name='" + name + '\'' +", age=" + age +'}';}// 如果name和age相同,要返回相同的哈希值@Overridepublic 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;}/*    @Overridepublic 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);}*/@Overridepublic 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 {@Testpublic 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;}@Overridepublic 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);}@Overridepublic int hashCode() {return Objects.hash(name, birthday);}@Overridepublic 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;}@Overridepublic 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);}@Overridepublic int hashCode() {return Objects.hash(year, month, day);}@Overridepublic 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 {@Testpublic 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;}@Overridepublic 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());}@Overridepublic int hashCode() {// 这里直接重写一次hashCode方法即可return Objects.hash(name, birthday.year, birthday.month, birthday.day);}@Overridepublic 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;}@Overridepublic 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 {@Testpublic 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;}@Overridepublic String toString() {return "Car{" +"name='" + name + '\'' +", price=" + price +'}';}// 重写equals和hash方法@Overridepublic 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);}@Overridepublic 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 {@Testpublic void getExercise() {// Map接口具有的特点// 常用String类作为Map的keyMap 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<key,value>接口,里面存放的是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 {@Testpublic 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 {@Testpublic 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找到对应的valueSystem.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$NodeMap.Entry entry = (Map.Entry) next;System.out.println("key = " + entry.getKey() + "  value = " + entry.getValue());}}}

课后练习

package com.Map;import org.junit.Test;import java.util.*;/*** @author wty* @date 2022/10/9 12:41*/
public class AfterClassExercise {@Testpublic 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) 是对象Workersif (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;}@Overridepublic 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 {@Testpublic 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 32hashMap.put(new Cat("小蓝", 10) , "no10.Jack"); // 扩容table 64hashMap.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;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic 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.javapackage 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 {@Testpublic 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 {@Testpublic 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.NullPointerExceptionproperties.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() {@Overridepublic 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<? super K> var1) {*         this.comparator = var1; 把new Comparator() 给到TreeMap的comparator属性*     }*/System.out.println("---字符串长度大小比较---");TreeSet treeSet2 = new TreeSet(new Comparator() {@Overridepublic 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 {@Testpublic 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() {@Overridepublic 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() {@Overridepublic 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 {@Testpublic 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() {@Overridepublic 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对象的所有旧值

@Testpublic 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() {@Overridepublic 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() {@Overridepublic 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.IndexOutOfBoundsExceptionArrayList 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 {@Testpublic 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());}}}@Testpublic 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;}@Overridepublic 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 {@Testpublic 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;}@Overridepublic 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 {@Testpublic 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;}@Overridepublic 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 {@Testpublic 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*/@Overridepublic 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集合 自学笔记(Java30天基础)相关推荐

  1. Java开发入门教程!韩顺平java数据结构课堂笔记

    摘要 Apache Kafka是一个分布式消息发布订阅系统.它最初由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统( a distributed commit log),之后成为Ap ...

  2. 【韩顺平Linux】学习笔记1

    [韩顺平Linux]学习笔记1 一.网络连接的三种方式 二.虚拟机克隆 三.虚拟机快照 四.虚拟机迁移和删除 五.VMtools 六.Linux目录结构 七.远程登录和文件传输 一.网络连接的三种方式 ...

  3. 韩顺平 java坦克大战_坦克大战完整版(韩顺平java)

    [实例简介] 坦克大战完整源代码(韩顺平java视频配套) [实例截图] [核心代码] 5i86q5 └── 源码 └── Class14 ├── 111.wav ├── bin │   ├── bo ...

  4. Java 集合学习笔记:Collection

    Java 集合学习笔记:Collection UML 简介 方法和说明 JDK8 新增 `default` 方法 AbstractCollection isEmpty contains(Object ...

  5. 韩顺平Java自学笔记 反射

    一.反射入门案例 目录 一.反射入门案例 二.反射的机制 1.反射的原理 2.反射相关的类 3.反射的优点和缺点 三.Class类详解 1.Class类的特征 2.Class的常用方法 3.获取Cla ...

  6. Java笔记(韩顺平Java基础12-14章)

    Java学习笔记(第12章 P444-P459)(第13章P460-P498)(第14章P499-P553) 第12章 异常-Exception 异常介绍 编译异常 异常处理 try-catch异常处 ...

  7. 基于Java机器学习自学笔记(第81-87天:CNN卷积神经网络的入门到全代码编写)

    注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 1. CN ...

  8. 韩顺平Java学习 泛型

    目录 一.泛型的语法 1.传统的方法遍历集合存在的问题 2.使用泛型来解决传统集合添加元素带来的问题 3.泛型使用介绍 4.泛型的使用细节 5.泛型课堂练习 二.自定义泛型 1.自定义泛型类的规范 ​ ...

  9. 韩顺平java基础——坦克大战(含有线程、I\O流的讲解)

    写在最前边: 研究生一枚,为后端实习和未来工作打基础.无意间发现韩顺平老师的课程,细心细致,讲课和吴恩达老师一样,都是保姆式讲解,各种基础知识都会补充,爱了. 韩顺平老师课程地址:https://ww ...

  10. 基于 Java 机器学习自学笔记 (第61-62天:ID3决策树)

    注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 一.关于决 ...

最新文章

  1. 学习,思维三部曲:WHAT、HOW、WHY
  2. 采用UDP协议实现PIC18F97J60 ethernet bootloader
  3. java mvc 实际分层_SpringMVC体系分层模式原理图解
  4. go语言 数组 map整体json
  5. 阿里专家杜万:Java响应式编程,一文全面解读
  6. Jenkins操作手册
  7. 全国各高校开学时间汇总!
  8. mysql 查询 更新属性值_MySQL-在一个查询中更新具有不同值的多行
  9. 简述mysql完全备份过程_【SQL】MySQL之使用mysqldump全备份及恢复过程详解_MySQL
  10. Duplicate File Finder pro如何查找删除相似照片
  11. 黑马程序员2022年最新软件测试学习路线
  12. 安卓玩机教程---全机型安卓4----安卓12 框架xp edx lsp安装方法
  13. html用post怎么加密,post提交数据如何加密
  14. MATLAB实战系列(十三)-Matlab绘制柱形图使用技巧解答(附Matlab代码)
  15. swagger注解的使用
  16. 通过笔记本wifi共享到以太网接口方法----令嵌入式设备接入互联网
  17. 网吧玩吃鸡提示服务器维护,绝地求生游戏更新维护给网吧带来的影响
  18. 打印机无法打印测试页
  19. 一款基于RFID的固定资产管理系统
  20. (视频) 《快速创建网站》3.4 网站改版3分钟搞定 - WordPress主题安装和备份

热门文章

  1. Java cms 孔浩老师 完整视频加源码 共131集 百度网盘永久链接 无需密码解压
  2. 数学建模-非线性规划模型
  3. 智驾科技MAXIEYE完成3亿元B轮融资,暂未取得品牌同名商标
  4. java heapdump 分析工具_Heapdump分析软件
  5. 【经典】具有中国特色的脑筋急转弯
  6. FlyMcu - 用于STM32芯片ISP串口程序一键下载的免费软件
  7. Asp.net自定义控件开发任我行(7)-注册自定义事件
  8. GlobalMapper20使用控制点对地形数据(高程数据)进行高程纠正(高程拟合/纠偏/配准)
  9. pgsql与mysql数据类型对比_PostgreSQL和mysql数据类型对比兼容
  10. 高校科研管理系统源代码_加强医院科研管理系统提升科研水平