集合体系图
老韩解读
1.集合主要是两组(单列集合,双列集合)
2.Collection 接口有两个重要的子接口 List Set 他们的实现子类都是单列集合
3.Map 接口的实现子类都是双列集合 存放的是Key-Value
4.把老师的两张图记住
单列集合双列集合演示
ArrayList arrayList=new ArrayList();
arrayList.add("jack");
arrayList.add("tom");
HashMap hashMap=new HashMap();
hashMap.put("NO1","北京");
hashMap.put("NO2","上海");
Collection
Collection接口的常用方法
代码演示
List list=new ArrayList();
//add:添加单个元素
list.add("Lmy");
list.add(10);
list.add(true);
System.out.println("list="+list);
//remove:删除指定元素
list.remove(0); //删除指定元素
System.out.println("list="+list);
list.remove("Lmy"); //指定删除某个元素
System.out.println("list="+list);
//contains:查找元素是否存在
System.out.println(list.contains(10));
//size:获取元素个数
System.out.println(list.size());
//isEmpty:判断是否为空
System.out.println(list.isEmpty());
//clear:清空
list.clear();
System.out.println("list="+list);
//addAll:添加多个元素
ArrayList list2 = new ArrayList<>();
list2.add("三国演义");
list2.add("红楼梦");
list.addAll(list2);
System.out.println("list="+list);
//containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list2));
//removeAll:删除多个元素
list.add("聊斋");
list.removeAll(list2);
System.out.println("list="+list);
Collection 接口遍历元素方式 1-使用 Iterator(迭代器)
迭代器的使用案例
package com.hspedu.collection;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
/**
* @ClassName CollectionIterator
* @Description TODO
* @Author lmy
* @Date 2022/6/14 22:26
**/
public class CollectionIterator {
@SuppressWarnings({"all"})
public static void main(String[] args) {
Collection col = new ArrayList();
col.add(new Book("三国演义", "罗贯中", 10.1));
col.add(new Book("小李飞刀", "古龙", 5.1));
col.add(new Book("红楼梦", "曹雪芹", 34.6));
// System.out.println("col="+col);
//现在老鼠希望能够遍历 col集合
//1. 先得到col对应的迭代器
Iterator iterator = col.iterator();
//2. 使用while循环遍历
// while (iterator.hasNext()){ //iterator.hasNext() 判断是否还有数据
// //返回下一个元素 类型是object
// Object obj = iterator.next();
// System.out.println("obj="+obj);
// }
//老师教大家一个快捷键 快速生成while 快捷键itit
//显示所有的快捷键的快捷键 ctrl(command)+j
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
//3. 当退出while循环后 这时iterator迭代器 指向最后的元素
//iterator.next(); //NoSuchElementException
//4. 如果希望再次遍历 需要重置我们的迭代器
iterator=col.iterator();
System.out.println("===第二次遍历===");
while (iterator.hasNext()){
Object obj=iterator.next();
System.out.println("obj="+obj);
}
}
}
class Book{
private String name;
private String author;
private double price;
public Book(String name, String author, double price) {
this.name = name;
this.author = author;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
Collection 接口遍历对象方式 2-for 循环增强
增强for循环的使用案例
package com.hspedu.collection;
import java.util.ArrayList;
import java.util.Collection;
/**
* @ClassName CollectionFor
* @Description TODO
* @Author lmy
* @Date 2022/6/14 23:00
**/
public class CollectionFor {
@SuppressWarnings({"all"})
public static void main(String[] args) {
Collection col = new ArrayList();
col.add(new Book("三国演义", "罗贯中", 10.1));
col.add(new Book("小李飞刀", "古龙", 5.1));
col.add(new Book("红楼梦", "曹雪芹", 34.6));
//老韩解读
//1. 使用增强for 在Collection集合
//2. 增强for 底层仍然是迭代器
//3. 增强for可以理解成就是简化版本的 迭代器遍历
//4. 快捷键方式 I 或 iter
for (Object book : col) {
System.out.println("book="+book);
}
//增强for 也可以直接在数组使用
int[] nums={1,8,10,90};
for (int i : nums) {
System.out.println("i="+i);
}
}
}
Collection课堂练习
代码
package com.hspedu.collection;
import java.util.ArrayList;
import java.util.Iterator;
/**
* @ClassName CollectionExercise
* @Description TODO
* @Author lmy
* @Date 2022/6/14 23:16
**/
public class CollectionExercise {
public static void main(String[] args) {
ArrayList arrayList=new ArrayList();
Dog d1=new Dog("Lmy",18);
Dog d2=new Dog("Lj",19);
arrayList.add(d1);
arrayList.add(d2);
//迭代器遍历
System.out.println("迭代器遍历:");
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
System.out.println("增强for循环遍历");
//增强for循环遍历
for (Object obj : arrayList) {
System.out.println(obj);
}
}
}
class Dog{
private String name;
private int age;
public Dog() {
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
List接口
List接口的特点
1. List集合类中元素有序(即添加顺序和取出顺序一致) 且可重复
2. List集合中的每个元素都有其对应的顺序索引 即支持索引 索引从0开始
代码演示
public class List_ {
public static void main(String[] args) {
//1. List集合类中元素有序(即添加顺序和取出顺序一致) 且可重复[案例]
List list=new ArrayList();
list.add("Jack");
list.add("Tom");
list.add("Mary");
//2. List集合中的每个元素都有其对应的顺序索引 即支持索引
// 索引从0开始
System.out.println(list.get(2)); //Mary
}
}
List接口常用方法
代码演示
package com.hspedu.list_;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName ListMethod
* @Description TODO
* @Author lmy
* @Date 2022/6/14 23:54
**/
public class ListMethod {
@SuppressWarnings({"all"})
public static void main(String[] args) {
List list = new ArrayList();
list.add("张三");
list.add("李四");
//void add(int index, Object ele):在index位置插入ele元素
//在index = 1的位置插入一个对象
list.add(1,"王五");
System.out.println("list=" + list);
//boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
List list2 = new ArrayList();
list2.add("李铭洋");
list2.add("李杰");
list.addAll(1, list2);
System.out.println("list=" + list);
//Object get(int index):获取指定index位置的元素
//说过
//int indexOf(Object obj):返回obj在集合中首次出现的位置
System.out.println(list.indexOf("李铭洋"));//1
//int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
list.add("韩顺平");
System.out.println("list=" + list);
System.out.println(list.lastIndexOf("韩顺平"));//5
//Object remove(int index):移除指定index位置的元素,并返回此元素
list.remove(0);
System.out.println("list=" + list);
//Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
list.set(1, "玛丽");
System.out.println("list=" + list);
//List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
// 注意返回的子集合 fromIndex <= subList < toIndex
List returnlist = list.subList(0, 2);
System.out.println("returnlist=" + returnlist);
}
}
List 接口课堂练习1
代码演示
package com.hspedu.list_;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @ClassName ListExercise
* @Description TODO
* @Author lmy
* @Date 2022/6/15 00:11
**/
public class ListExercise {
public static void main(String[] args) {
List list=new ArrayList();
for (int i = 0; i < 12; i++) {
list.add("hello"+i);
}
System.out.println("list="+list);
//在2号位插入一个元素韩顺平教育
list.add(1,"韩顺平教育");
System.out.println("list="+list);
//获取第五个元素
System.out.println(list.get(4));
//删除第六个元素
list.remove(5);
System.out.println("list="+list);
//修改第七个元素
list.set(6,"三国演义");
System.out.println("list="+list);
//使用迭代器遍历集合
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj="+obj);
}
}
}
List 的三种遍历方式 [ArrayList, LinkedList,Vector]
代码演示
package com.hspedu.list_;
import java.util.*;
/**
* @ClassName ListFor
* @Description TODO
* @Author lmy
* @Date 2022/6/15 08:23
**/
public class ListFor {
public static void main(String[] args) {
//List的实现子类 Vector LinkededList
List list=new ArrayList();
//List list=new Vector();
//List list=new LinkedList();
list.add("北京烤鸭");
list.add("鱼香肉丝");
list.add("襄阳牛肉面");
list.add("武汉热干面");
//遍历
//1. 迭代器
System.out.println("这是迭代器方式遍历:");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
//2.增强for循环
System.out.println("这是增强for循环遍历");
for (Object obj : list) {
System.out.println(obj);
}
//3.普通for循环
System.out.println("这是普通for循环遍历");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
List 接口课堂练习2
代码演示
package com.hspedu.list_;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
/**
* @ClassName ListExercise02
* @Description TODO
* @Author lmy
* @Date 2022/6/15 08:30
**/
public class ListExercise02 {
public static void main(String[] args) {
List list=new ArrayList();
// List list=new Vector();
// List list=new LinkedList();
list.add(new Book("红楼梦","曹雪芹",100));
list.add(new Book("西游记","吴承恩",70));
list.add(new Book("水浒传","施耐庵",90));
list.add(new Book("三国演义","罗贯中",80));
//遍历
System.out.println("排序前:");
for (Object obj : list) {
System.out.println(obj);
}
//如何对集合进行排序(使用冒泡排序)
sort(list);
System.out.println("排序后");
for (Object obj : list) {
System.out.println(obj);
}
}
/**
* 实现思路
* 1.使用冒泡排序
* 2.使用list.get()方法 取出Book对象 这里拿Book1 Book2来举例
* 3.如果后一个对象(Book2)对象的价格大于前一个(Book1)对象的价格
* 4.使用list.set()方法 将后一个对象(Book2)赋值给前一个对象(Book1)的位置 将前一个对象(Book1)赋值给后一个对象(Book2)的位置 通俗一点就是交换双方位置
*/
//静态方法
public static void sort(List list){
//遍历
int listSize = list.size();
for (int i = 0; i < listSize - 1; i++) {
for (int j = 0; j <listSize - i - 1; j++) {
//取出对象Book
Book book1=(Book) list.get(j);
Book book2=(Book) list.get(j+1);
if (book1.getPrice()>book2.getPrice()){
list.set(j,book2);
list.set(j+1,book1);
}
}
}
}
}
ArrayList 底层结构和源码分析
ArrayList 的注意事项
代码演示
package com.hspedu.list_;
import java.util.ArrayList;
/**
* @ClassName ArrayListDetail
* @Description TODO
* @Author lmy
* @Date 2022/6/15 09:00
**/
public class ArrayListDetail {
public static void main(String[] args) {
//ArrayList 是线程不安全的 可以看源码 没有 synchronized
/**
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
*/
ArrayList arrayList=new ArrayList();
arrayList.add(null);
arrayList.add("Lmy");
arrayList.add(null);
System.out.println(arrayList);
}
}
ArrayList 的底层操作机制源码分析(重点,难点.)
Vector 底层结构和源码剖析
Vector 的基本介绍
package com.hspedu.list_;
import java.util.Vector;
/**
* @ClassName Vector_
* @Description TODO
* @Author lmy
* @Date 2022/6/15 12:16
**/
public class Vector_ {
public static void main(String[] args) {
//无参构造器
Vector vector=new Vector();
//有参构造器
//Vector vector=new Vector(8);
for (int i = 0; i < 10; i++) {
vector.add(i);
}
vector.add(100);
//老韩解读
/**
* 1.new Vector(); 底层
* public Vector() {
* this(10);
* }
*
* 2. vector.add(i)
* 2.1 下面这个方法就添加数据到vector集合
* public synchronized boolean add(E e) {
* modCount++;
* ensureCapacityHelper(elementCount + 1);
* elementData[elementCount++] = e;
* return true;
* }
* 2.2 确定是否需要扩容 条件 : minCapacity - elementData.length > 0
* private void ensureCapacityHelper(int minCapacity) {
* // overflow-conscious code
* if (minCapacity - elementData.length > 0)
* grow(minCapacity);
* }
* 2.3 如果需要的数组大小 不够用就扩容 扩容的算法
* // int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
* // 即oldCapacity+oldCapacity 扩容两倍
*
* private void grow(int minCapacity) {
* // overflow-conscious code
* int oldCapacity = elementData.length;
* int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
* if (newCapacity - minCapacity < 0)
* newCapacity = minCapacity;
* if (newCapacity - MAX_ARRAY_SIZE > 0)
* newCapacity = hugeCapacity(minCapacity);
* elementData = Arrays.copyOf(elementData, newCapacity);
* }
*/
}
}
Vector 和 ArrayList 的比较
LinkedList 底层结构
LinkedList 的全面说明
LinkedList 的底层操作机制
代码演示
package com.hspedu.list_;
/**
* @ClassName LinkedList01
* @Description TODO
* @Author lmy
* @Date 2022/6/15 13:24
**/
public class LinkedList01 {
public static void main(String[] args) {
//模拟一个简单的双向链表
Node jack=new Node("jack");
Node tom=new Node("tom");
Node hsp=new Node("老韩");
//连接三个结点 形成双向链表
//jack -> tom -> hsp
jack.next=tom;
tom.next=hsp;
//hsp -> tom -> jack
hsp.pre=tom;
tom.pre=jack;
Node first=jack; //让first引用指向jack 就是双向链表的头结点
Node last=hsp; //让last引用指向hsp 就是双向链表的尾结点
//演示: 从头到尾进行遍历
System.out.println("===从头到尾遍历===");
while (true){
if (first==null){
break;
}
//输出first信息
System.out.println(first);
//省略此句 程序死循环
first=first.next;
}
//演示: 从尾到头进行遍历
System.out.println("===从尾到头遍历===");
while (true){
if (last==null){
break;
}
//输出last信息
System.out.println(last);
//省略此句 程序死循环
last=last.pre;
}
//演示链表的添加对象/数据,是多么的方便
//要求,是在 tom --------- 老韩直接,插入一个对象 smith
//1.先创建一个 Node结点 name就是smith
Node smith=new Node("smith");
smith.next=hsp;
smith.pre=tom;
hsp.pre=smith;
tom.next=smith;
//让 first 再次指向 jack
first=jack;
//演示: 从头到尾进行遍历
System.out.println("===从头到尾遍历===");
while (true){
if (first==null){
break;
}
//输出first信息
System.out.println(first);
//省略此句 程序死循环
first=first.next;
}
//让 first 再次指向 hsp
last=hsp;
//演示: 从尾到头进行遍历
System.out.println("===从尾到头遍历===");
while (true){
if (last==null){
break;
}
//输出last信息
System.out.println(last);
//省略此句 程序死循环
last=last.pre;
}
}
}
//定义一个Node类 Node对象 表示双向链表的一个结点
class Node{
public Object item; //真正存放数据的地方
public Node next; //指向后一个节点
public Node pre; //指向前一个节点
public Node(Object item) {
this.item = item;
}
@Override
public String toString() {
return "Node name="+item;
}
}
LinkedList 的增删改查案例
代码演示
package com.hspedu.list_;
import java.util.Iterator;
import java.util.LinkedList;
/**
* @ClassName LinkedListCRUD
* @Description TODO
* @Author lmy
* @Date 2022/6/15 15:29
**/
public class LinkedListCRUD {
public static void main(String[] args) {
LinkedList linkedList=new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
System.out.println("linkedList:"+linkedList);
//演示一个删除删除结点的
linkedList.remove(); //这里默认删除的是第一个结点
//linkedList.remove(2);
System.out.println("linkedList="+linkedList);
//修改某个结点对象
linkedList.set(1,"999");
System.out.println("linkedList="+linkedList);
//得到某个结点对象
Object o = linkedList.get(1);
System.out.println(o);
//因为LinkedList 是实现了List接口 遍历方式增强for 或者 迭代器 或者普通for循环
//迭代器
System.out.println("===LinkedList遍历迭代器===");
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj="+obj);
}
//增强for循环
System.out.println("===LinkedList增强for===");
for (Object obj : linkedList) {
System.out.println("obj="+obj);
}
//普通for循环
System.out.println("===LinkedList普通for===");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println("obj="+linkedList.get(i));
}
//老韩源码阅读
/**
* 1. LinkedList linkedList=new LinkedList();
* public LinkedList() {}
* 2. 这时linkedList的属性 first=null last=null
* 3. 执行 添加
* public boolean add(E e) {
* linkLast(e);
* return true;
* }
* 4. 将新的结点 加入到双向链表的最后
* void linkLast(E e) {
* final Node<E> l = last;
* final Node<E> newNode = new Node<>(l, e, null);
* last = newNode;
* if (l == null)
* first = newNode;
* else
* l.next = newNode;
* size++;
* modCount++;
* }
*/
/**
* 老韩读源码 inkedList.remove(); //这里默认删除的是第一个结点
* 1. 执行 removeFirst
* public E remove() {
* return removeFirst();
* }
* 2. 执行
* public E removeFirst() {
* final Node<E> f = first; //把第一个值赋值给f
* if (f == null) //如果对象等于空 则抛出异常
* throw new NoSuchElementException();
* return unlinkFirst(f); //如果对象不等于空 则执行unlinkFirst(f) 方法
* }
* 3. 执行 unlinkFirst 将f指向的双向链表的第一个结点拿掉
* private E unlinkFirst(Node<E> f) {
* // assert f == first && f != null;
* final E element = f.item; //获取第一个的值
* final Node<E> next = f.next; //把下一个对象赋值给next
* f.item = null; //第一个值为空
* f.next = null; // help GC //第一个值和第二值的连接为空(断开)
* first = next; //把下一个对象赋值给first
* if (next == null) //判断是否为空
* last = null;
* else
* next.prev = null; //第二个和第一个值的连接为空(断开)
* size--;
* modCount++;
* return element;
* }
*
*/
}
}
ArrayList 和 LinkedList 比较
Set接口
Set 接口基本介绍
Set 接口的常用方法
和 List 接口一样, Set 接口也是 Collection 的子接口,因此,常用方法和 Collection 接口一样.
Set 接口的遍历方式
Set 接口的常用方法举例
package com.hspedu.set_;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* @ClassName SetMethod
* @Description TODO
* @Author lmy
* @Date 2022/6/15 16:42
**/
public class SetMethod {
public static void main(String[] args) {
//老韩解读
//1. 以Set 接口的实现类 HashSet 来讲解Set 接口的方法
//2. set接口的实现类的对象(Set接口对象) 不能存放重复的元素 可以添加一个null
//3. set接口对象存放数据是无序(即添加的顺序和取出的顺序不一致)
//4. 注意: 取出的顺序虽然不是添加的顺序 但是他是固定的
Set set=new HashSet();
set.add("Jack");
set.add("Lmy");
set.add("Lj");
set.add("Jack"); //重复
set.add("hsp");
set.add("marry");
set.add(null);
set.add(null); //再次添加null
for (int i = 0; i < 10; i++) {
System.out.println("set="+set);
}
//遍历
//方式一:迭代器
System.out.println("===迭代器遍历Set集合===");
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
set.remove(null);
//方式二:增强for
System.out.println("===增强for循环遍历Set集合===");
for (Object obj : set) {
System.out.println(obj);
}
//Set 接口对象不可以通过索引来获取(普通for循环)
}
}
Set 接口实现类-HashSet
HashSet 的全面说明
代码演示
public class HashSet_ {
public static void main(String[] args) {
//老韩解读
/**
* 1.构造器走的源码
* public HashSet() {
* map = new HashMap<>();
* }
* 2.HashSet 可以存放null 但是只能有一个null 即元素不可以重复
*/
Set hashSet=new HashSet();
hashSet.add(null);
hashSet.add(null);
System.out.println("hashSet="+hashSet);
}
}
HashSet 案例说明
package com.hspedu.set_;
import java.util.HashSet;
/**
* @ClassName HashSet01
* @Description TODO
* @Author lmy
* @Date 2022/6/15 17:16
**/
public class HashSet01 {
public static void main(String[] args) {
HashSet set=new HashSet();
//说明
//1.在执行add方法后 会返回一个boolean值
//2.如果添加成功 返回true 否则返回false
System.out.println(set.add("john")); //true
System.out.println(set.add("lucy")); //true
System.out.println(set.add("john")); //false
System.out.println(set.add("jack")); //true
System.out.println(set.add("rose")); //true
System.out.println("删除前:");
System.out.println("set="+set); //set=[john, rose, lucy, jack]
set.remove("john");
System.out.println("删除后:");
System.out.println("set="+set); //set=[rose, lucy, jack]
//
set=new HashSet();
System.out.println("重置后:");
System.out.println("set="+set);
//4.Hashset 不能添加相同的元素/数据
set.add("lucy");
set.add("lucy");
//个人理解: new一个对象 他们的地址值不一样 所以他们都可以添加Set集合中
set.add(new Dog("tom"));// com.hspedu.set_.Dog@6bc7c054
set.add(new Dog("tom"));// com.hspedu.set_.Dog@75b84c92
//需要重写toString()方法 否则打印的是地址值
//set=[com.hspedu.set_.Dog@6bc7c054, com.hspedu.set_.Dog@75b84c92, lucy]
//set=[Dog{name='tom'}, Dog{name='tom'}, lucy]
System.out.println("set="+set);
//在加深一下 非常经典的面试题
//看源码 做分析 先给小伙伴留一个坑 以后讲完源码 你就一目了然了
//去看他的源码 即 add 到底发生了什么?=> 底层机制
set.add(new String("hsp")); //ok
set.add(new String("hsp")); //加入不了
System.out.println("set="+set);
}
}
class Dog{ //定义了一个Dog类
private String name;
public Dog(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
'}';
}
}
HashSet 底层机制说明
代码演示1
package com.hspedu.set_;
/**
* @ClassName HashSetSource
* @Description TODO
* @Author lmy
* @Date 2022/6/15 19:57
**/
public class HashSetStructure{
public static void main(String[] args) {
//模拟一个HashSet的底层 (HashMap的底层结构)
//1.创建一个数组 数组的类型是 Node[]
//2.有些人 直接把Node[] 数组称为 表
Node[] table=new Node[16];
//3.创建结点
Node john = new Node("john", null);
table[2]=john; //把john放到 table表的索引为2的位置
Node jack = new Node("jack", null);
john.next=jack;//将jack 结点挂载到john
Node rose=new Node("rose",null);
jack.next=rose;//将rose 结点挂载到jack
Node lucy = new Node("lucy", null);
table[3]=lucy; //把lucy放到 table表的索引为3的位置
System.out.println("table="+table);
}
}
class Node{ //结点 存储数据 可以指点下一个结点 从而形成链表
Object item; //存放数据
Node next; //指向下一个结点
public Node(Object item, Node next) {
this.item = item;
this.next = next;
}
}
代码演示2
package com.hspedu.set_;
import java.util.HashSet;
/**
* @ClassName HashSetSource
* @Description TODO
* @Author lmy
* @Date 2022/6/15 21:07
**/
public class HashSetSource {
public static void main(String[] args) {
HashSet hashSet=new HashSet();
hashSet.add("java"); //到此为止 第1次add分析完毕
hashSet.add("php"); //到此为止 第2次add分析完毕
hashSet.add("java");
System.out.println("set="+hashSet);
/**
* 老韩对HashSet的源码解读
* 1.执行 HashSet()
* public HashSet() {
* map = new HashMap<>();
* }
* 2.执行 add()
* public boolean add(E e) { //e="java"
* return map.put(e, PRESENT)==null; //(static)PRESENT = new Object();
* }
* 3.执行 put() 该方法会执行我们的hash(key) 得到key对应的hash值 算法是 h = key.hashCode()) ^ (h >>> 16)
* public V put(K key, V value) { //key="java" value=PRESENT 共享
* return putVal(hash(key), key, value, false, true);
* }
* 4.执行
* final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
* boolean evict) {
* Node<K,V>[] tab; Node<K,V> p; int n, i; //定义了辅助变量
* //table 就是 HashMap 的一个数组 类型是 Node[]
* //if 语句表示如果当前table 是 null 或者>=0
* //就是第一次扩容到16个空间
* if ((tab = table) == null || (n = tab.length) == 0)
* n = (tab = resize()).length;
* //(1)根据key 得到hash 去计算该key应该存放到table表的哪个索引位置
* //并把这个位置的对象 赋给 p
* //(2)判断p是否为null
* //(2.1)如果p为null 表示还没有存放元素 就创建一个Node(key="java",value=PRESENT)
* //(2.2)就放在该位置 tab[i]= newNode(hash, key, value, null);
* if ((p = tab[i = (n - 1) & hash]) == null)
* tab[i] = newNode(hash, key, value, null);
* else {
* //一个开发技巧提示: 在需要局部变量(辅助变量)时候,再创建
* Node<K,V> e; K k;
* //如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
* //并且满足 下面两个条件之一
* //(1) 准备加入的key 和 p指向的Node结点的key是同一个对象
* //(2) p指向的Node结点的key的equals() 和准备加入的key比较后相同
* //就不能加入
* if (p.hash == hash &&
* ((k = p.key) == key || (key != null && key.equals(k))))
* e = p;
* //再判断 p是不是一颗红黑树
* //如果是一颗红黑树 就调用putTreeVal()方法来进行添加
* else if (p instanceof TreeNode)
* e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
* else {
* //如果table对应索引位置 已经是一个链表了 就使用for循环比较
* //(1) 依次和该链表的每一个元素比较后 都不相同 则加入当该链表的最后
* // 注意在把元素添加到链表后 立即判断 该链表是否已已经达到8个结点
* // ,就调用treeifyBin() 对当前这个链表进行树化(转成红黑树)
* // 注意 在转成红黑树时 要进行判断 判断条件如下
* if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
* resize();
* 如果上面条件成立 先table扩容
* 只有上面条件不成立时,才进行转成红黑树
* //(2) 依次和该链表的每一个元素过程中 如果有相同情况 就直接break
* for (int binCount = 0; ; ++binCount) {
* if ((e = p.next) == null) {
* p.next = newNode(hash, key, value, null);
* if (binCount >= TREEIFY_THRESHOLD(8) - 1) // -1 for 1st
* treeifyBin(tab, hash);
* break;
* }
* if (e.hash == hash &&
* ((k = e.key) == key || (key != null && key.equals(k))))
* break;
* p = e;
* }
* }
* if (e != null) { // existing mapping for key
* V oldValue = e.value;
* if (!onlyIfAbsent || oldValue == null)
* e.value = value;
* afterNodeAccess(e);
* return oldValue;
* }
* }
* ++modCount;
* //size 就是我们每加入一个结点Node(k,v,h,next)
* if (++size > threshold)
* resize();
* afterNodeInsertion(evict);
* return null;
* }
*/
}
}
package com.hspedu.set_;
import java.util.HashSet;
import java.util.Objects;
/**
* @ClassName HashSetIncrement
* @Description TODO
* @Author lmy
* @Date 2022/6/16 00:36
**/
@SuppressWarnings({"all"})
public class HashSetIncrement {
public static void main(String[] args) {
/**
*
*HashSet底层是HashMap, 第一次添加时,table 数组扩容到 16,
*临界值(threshold)是 16*加载因子(loadFactor)是0.75 = 12
*如果table 数组使用到了临界值 12,就会扩容到 16 * 2 = 32,
*新的临界值就是 32*0.75 = 24, 依次类推
*/
HashSet hashSet=new HashSet();
// for (int i = 1; i <= 100; i++) {
// hashSet.add(i);
// }
/**
* 在Java8中, 如果一条链表的元素个数到达 TREEIFY_THRESHOLD(默认是 8 ),
* 并且table的大小 >= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),
* 否则仍然采用数组扩容机制
*/
// for (int i = 1; i <= 12; i++) {
// hashSet.add(new A(i));
// }
// System.out.println("hashset="+hashSet);
/**
* 当我们向hashset增加一个元素,-> Node -> 加入table , 就算是增加了一个size++
*/
for(int i = 1; i <= 7; i++) {//在table的某一条链表上添加了 7个A对象
hashSet.add(new A(i));//
}
for(int i = 1; i <= 7; i++) {//在table的另外一条链表上添加了 7个B对象
hashSet.add(new B(i));//
}
}
}
class A{
private int n;
public A(int n) {
this.n = n;
}
@Override
public int hashCode() {
return 100;
}
}
class B {
private int n;
public B(int n) {
this.n = n;
}
@Override
public int hashCode() {
return 200;
}
}
HashSet 课堂练习 1
代码演示
package com.hspedu.set_;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
/**
* @ClassName HashSetExercise
* @Description TODO
* @Author lmy
* @Date 2022/6/16 09:16
**/
public class HashSetExercise {
public static void main(String[] args) {
/**
*定义一个Employee类,该类包含:private成员属性name,age 要求:
*创建3个Employee 对象放入 HashSet中
*当 name和age的值相同时,认为是相同员工, 不能添加到HashSet集合中
*/
HashSet hashSet=new HashSet();
hashSet.add(new Employee("Lmy",18)); //ok
hashSet.add(new Employee("Lj",19)); //ok
hashSet.add(new Employee("Lmy",18)); //加入不成功
//遍历
System.out.println("===迭代器遍历===");
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
System.out.println("===增强for循环遍历===");
for (Object obj : hashSet) {
System.out.println(obj);
}
}
}
class Employee{
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//如果name 和 age 值相同,则返回相同的hash值
@Override
public boolean equals(Object o) {
//系统自动生成的
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age && Objects.equals(name, employee.name);
//自己写的
// Employee e1 = (Employee) o;//将Object向下转型为Person
// return this.name.equals(e1 .name) && this.age == e1 .age;
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
HashSet 课后练习 2
代码演示
package com.hspedu.set_;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
/**
* @ClassName HashSetExercise
* @Description TODO
* @Author lmy
* @Date 2022/6/16 09:16
**/
import java.util.HashSet;
import java.util.Objects;
public class HashSetExercise02 {
public static void main(String[] args) {
/**
* 定义一个Employee类 该类包含 private成员属性name,sal,birthday(MyDate类型)
* 其中 birthday为MyDate类型(属性包括:year,month,day)
* 要求:
* 1.创建3个Employee放入HashSet中
* 2.当name和birthday的值相同时,认为是相同员工,不能添加到HashSet集合中
*/
HashSet hashSet = new HashSet();
hashSet.add(new Employee01("Lmy",1000.0,new MyDate(2002,8,2)));
hashSet.add(new Employee01("Lj",1000.0,new MyDate(2001,8,2)));
hashSet.add(new Employee01("Lmy",1000.0,new MyDate(2002,8,2)));
//遍历
System.out.println("===迭代器遍历===");
Iterator iterator = hashSet.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
System.out.println("===增强for循环遍历==");
for (Object obj : hashSet) {
System.out.println(obj);
}
}
}
class Employee01{
private String name;
private Double sal;
private MyDate birthday;
public Employee01(String name, Double sal, MyDate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee01 that = (Employee01) o;
return Objects.equals(name, that.name) && Objects.equals(birthday, that.birthday);
}
@Override
public int hashCode() {
return Objects.hash(name, birthday);
}
@Override
public String toString() {
return "Employee01{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
}
class MyDate{
private Integer year;
private Integer month;
private Integer day;
public MyDate(Integer year, Integer month, Integer day) {
this.year = year;
this.month = month;
this.day = day;
}
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
public Integer getMonth() {
return month;
}
public void setMonth(Integer month) {
this.month = month;
}
public Integer getDay() {
return day;
}
public void setDay(Integer day) {
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 +
'}';
}
}
Set 接口实现类-LinkedHashSet
LinkedHashSet 的全面说明
代码演示
package com.hspedu.set_;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @ClassName LinkedHashSetSource
* @Description TODO
* @Author lmy
* @Date 2022/6/16 10:33
**/
@SuppressWarnings({"all"})
public class LinkedHashSetSource {
public static void main(String[] args) {
//分析一下LinkedHashSet的底层机制
Set set=new LinkedHashSet();
set.add(new String("AA"));
set.add(456);
set.add(456);
set.add(new Customer("刘",1001));
set.add(123);
set.add("HSP");
System.out.println("set="+set);
//老韩解读
//1. LinkedHashSet 加入顺序和取出元素/数据的顺序一致
//2. LinkedHashSet 底层维护的是一个LinkedHashMap(是HashMap的子类)
//3. LinkedHashSet 底层结构(数组table+双向链表)
//4. 添加第一次时 直接将 数组table 扩容到16 存放的结点类型是 LinkedHashMap$Entry
//5. 数组是HashMap$Node[] 存放的元素/数据是 LinkedHashMap$Entry类型
/**
* //继承关系是在内部类完成
* static class Entry<K,V> extends HashMap.Node<K,V> {
* Entry<K,V> before, after;
* Entry(int hash, K key, V value, Node<K,V> next) {
* super(hash, key, value, next);
* }
* }
*/
}
}
class Customer{
private String name;
private int no;
public Customer(String name, int no) {
this.name = name;
this.no = no;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", no=" + no +
'}';
}
}
LinkedHashSet 课后练习题
代码演示
package com.hspedu.set_;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Objects;
/**
* @ClassName LinkedHashSetExercise
* @Description TODO
* @Author lmy
* @Date 2022/6/16 11:34
**/
public class LinkedHashSetExercise {
public static void main(String[] args) {
HashSet linkedHashSet=new LinkedHashSet();
linkedHashSet.add(new Car("奥拓",1000.0)); //ok
linkedHashSet.add(new Car("奥迪",300000.0)); //ok
linkedHashSet.add(new Car("法拉利",10000000.0)); //ok
linkedHashSet.add(new Car("奥迪",300000.0)); //加入不了
linkedHashSet.add(new Car("保时捷",70000000.0)); //ok
linkedHashSet.add(new Car("奥迪",300000.0)); //加入不了
Iterator iterator = linkedHashSet.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
}
}
/**
* Car类(属性name,price) 如果name和price一样 则认为是相同元素 就不能添加
*/
class Car{
private String name;
private Double price;
public Car(String name, Double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
//重写equals 方法 和 hashCode
//当 name 和 price 相同时, 就返回相同的 hashCode 值, equals返回t
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return Objects.equals(name, car.name) && Objects.equals(price, car.price);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
Map 接口
Map 接口实现类的特点 [很实用]
代码演示
package com.hspedu.map_;
import java.util.HashMap;
/**
* @ClassName Map_
* @Description TODO
* @Author lmy
* @Date 2022/6/16 12:12
**/
@SuppressWarnings({"all"})
public class Map_ {
public static void main(String[] args) {
//老韩解读Map 接口实现类的特点 使用实现类HashMap
//1.Map与Collection 并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
//2.Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
//3.Map中的key不允许重复,原因和HashSet 一样,前面分析过源码.
//4.Map中的value可以重复
//5.Map的key可以为null,value也可以为null,注意key为null只能有一个,value为null可以多个
//6.常用String类作为Map的key
//7.key和value之间存在单向一对一关系即通过指定的key总能找到对应的value
HashMap map = new HashMap();
map.put("no1","韩顺平"); //k-v
map.put("no2","李铭洋"); //k-v
map.put("no1","李杰"); //当有相同的k,就等价于替换
map.put("no3","李铭洋"); //Map中的value可以重复
map.put(null,null); //k-v
map.put(null,"abc"); //等价替换
map.put("no4",null); //k-v
map.put("no5",null); //k-v
map.put(1,"张三"); //k-v
map.put(new Object(),"金毛狮王"); //k-v
//通过get 方法 传入key 获取对应的value
System.out.println(map.get("no3"));
System.out.println("map="+map);
}
}
package com.hspedu.map_;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @ClassName MapSource
* @Description TODO
* @Author lmy
* @Date 2022/6/16 13:13
**/
@SuppressWarnings({"all"})
public class MapSource {
public static void main(String[] args) {
Map map=new HashMap();
map.put("no1","韩顺平"); //k-v
map.put("no2","张无忌"); //k-v
map.put(new Car(),new Person()); //k-v
//老韩解读
//1. k-v 最后是 HashMap$Node node = newNode(hash, key, value, null)
//2. k-v 为了方便程序员的遍历,还会 创建 EntrySet 集合 ,该集合存放的元素的类型 Entry, 而一个Entry
// 对象就有k,v EntrySet<Entry<K,V>> 即: transient Set<Map.Entry<K,V>> entrySet;
//3. entrySet 中, 定义的类型是 Map.Entry ,但是实际上存放的还是 HashMap$Node
// 这时因为 static class Node<K,V> implements Map.Entry<K,V>
//4. 当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历, 因为 Map.Entry 提供了重要方法
// K getKey(); V getValue();
Set set=map.entrySet();
System.out.println(set.getClass()); //HashMap$EntrySet
for (Object obj : set) {
//System.out.println(entry.getClass()); //HashMap$Node
//为了从 HashMap$Node 取出k-v
//1. 先做一个向下转型
Map.Entry entry=(Map.Entry) obj;
System.out.println(entry.getKey()+"="+entry.getValue());
}
Set set1 = map.keySet();
System.out.println(set1.getClass());
Collection values = map.values();
System.out.println(values.getClass());
}
}
class Car{
}
class Person{
}
Map 接口常用方法
代码演示
package com.hspedu.map_;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName MapMethod
* @Description TODO
* @Author lmy
* @Date 2022/6/16 14:28
**/
@SuppressWarnings({"all"})
public class MapMethod {
public static void main(String[] args) {
//演示map接口常用方法
Map map = new HashMap();
map.put("邓超", new Book("", 100));//OK
map.put("邓超", "孙俪");//替换-> 一会分析源码
map.put("王宝强", "马蓉");//OK
map.put("宋喆", "马蓉");//OK
map.put("刘令博", null);//OK
map.put(null, "刘亦菲");//OK
map.put("鹿晗", "关晓彤");//OK
map.put("hsp", "hsp的老婆");
System.out.println("map=" + map);
//remove:根据键删除映射关系
map.remove(null);
System.out.println("map=" + map);
//get:根据键获取值
Object val = map.get("鹿晗");
System.out.println("val=" + val);
//size:获取元素个数
System.out.println("k-v=" + map.size());
//isEmpty:判断个数是否为0
System.out.println(map.isEmpty());//F
//clear:清除k-v
//map.clear();
System.out.println("map=" + map);
//containsKey:查找键是否存在
System.out.println("结果=" + map.containsKey("hsp"));//T
}
}
class Book {
private String name;
private int num;
public Book(String name, int num) {
this.name = name;
this.num = num;
}
}
Map 接口遍历方法
代码演示
package com.hspedu.map_;
import java.util.*;
/**
* @ClassName MapFor
* @Description TODO
* @Author lmy
* @Date 2022/6/16 14:53
**/
@SuppressWarnings({"all"})
public class MapFor {
public static void main(String[] args) {
Map map = new HashMap();
map.put("邓超", "孙俪");
map.put("王宝强", "马蓉");
map.put("宋喆", "马蓉");
map.put("刘令博", null);
map.put(null, "刘亦菲");
map.put("鹿晗", "关晓彤");
//第一组: 先取出 所有的Key 通过Key 取出对应的Value
Set keySet = map.keySet();
//(1)增强for循环
System.out.println("-----第一种方式-----");
for (Object key : keySet) {
System.out.println(key+"->"+map.get(key));
}
//(2)迭代器
System.out.println("-----第二种方式-----");
Iterator iterator = keySet.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key+"->"+map.get(key));
}
//第二组: 把所有的value取出
Collection values = map.values();
//这里可以使用所有的Collection使用的遍历方法
//(1)增强for循环
System.out.println("-----取出所有的value 增强for-----");
for (Object value : values) {
System.out.println(value);
}
//(2)迭代器
System.out.println("-----取出所有的value 迭代器-----");
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
Object obj = iterator1.next();
System.out.println(obj);
}
//第三组: 通过EntrySet来获取 k-v
Set entrySet = map.entrySet(); //EntrySet<Map.Entry<K,V>
//(1)增强for
System.out.println("-----使用EntrySet的 增强for循环-----");
for (Object entry : entrySet) {
Map.Entry m=(Map.Entry) entry;
System.out.println(m.getKey()+"->"+m.getValue());
}
//(2)迭代器
System.out.println("-----使用EntrySet的 迭代器-----");
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Object entry = iterator2.next();
//System.out.println(next.getClass());//HashMap$Node -实现-> Map.Entry (getKey,getValue)
//向下转型 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "->" + m.getValue());
}
}
}
Map 接口课堂练习
代码演示
package com.hspedu.map_;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @ClassName MapExercise
* @Description TODO
* @Author lmy
* @Date 2022/6/16 15:40
**/
@SuppressWarnings({"all"})
public class MapExercise {
public static void main(String[] args) {
//完成代码
HashMap hashMap=new HashMap();
//添加对象
hashMap.put(1,new Emp("Lmy",10000.0,1));
hashMap.put(2,new Emp("Lj",30000.0,2));
hashMap.put(3,new Emp("Tom",20000.0,3));
//遍历2种方式
//并遍历显示工资>18000的员工(遍历方式最少两种)
//1. 使用keySet 增强for
System.out.println("===增强for循环===");
Set keySet = hashMap.keySet();
for (Object key : keySet) {
//先获取value
Emp emp = (Emp) hashMap.get(key);
if (emp.getSal()>18000){
System.out.println(emp);
}
}
//2. 使用EntrySet 迭代器
// 体现比较难的知识点
// 慢慢品,越品越有味道.
System.out.println("===迭代器===");
Set entrySet = hashMap.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
//通过entry 取得key 和 value
Emp emp=(Emp) entry.getValue();
if (emp.getSal()>18000){
System.out.println(emp);
}
}
}
}
/**
* 使用HashMap添加3个员工对象,要求
* 键:员工id
* 值:员工对象
*
* 并遍历显示工资>18000的员工(遍历方式最少两种)
* 员工类:姓名、工资、员工id
*/
class Emp {
private String name;
private double sal;
private int id;
public Emp(String name, double sal, int id) {
this.name = name;
this.sal = sal;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", sal=" + sal +
", id=" + id +
'}';
}
}
Map 接口实现类-HashMap
HashMap 小结
HashMap 底层机制及源码剖析
代码演示
package com.hspedu.map_;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @ClassName MapSource
* @Description TODO
* @Author lmy
* @Date 2022/6/16 13:13
**/
@SuppressWarnings({"all"})
public class MapSource {
public static void main(String[] args) {
Map map=new HashMap();
map.put("no1","韩顺平"); //k-v
map.put("no2","张无忌"); //k-v
map.put(new Car(),new Person()); //k-v
//老韩解读
//1. k-v 最后是 HashMap$Node node = newNode(hash, key, value, null)
//2. k-v 为了方便程序员的遍历,还会 创建 EntrySet 集合 ,该集合存放的元素的类型 Entry, 而一个Entry
// 对象就有k,v EntrySet<Entry<K,V>> 即: transient Set<Map.Entry<K,V>> entrySet;
//3. entrySet 中, 定义的类型是 Map.Entry ,但是实际上存放的还是 HashMap$Node
// 这时因为 static class Node<K,V> implements Map.Entry<K,V>
//4. 当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历, 因为 Map.Entry 提供了重要方法
// K getKey(); V getValue();
Set set=map.entrySet();
System.out.println(set.getClass()); //HashMap$EntrySet
for (Object obj : set) {
//System.out.println(entry.getClass()); //HashMap$Node
//为了从 HashMap$Node 取出k-v
//1. 先做一个向下转型
Map.Entry entry=(Map.Entry) obj;
System.out.println(entry.getKey()+"="+entry.getValue());
}
Set set1 = map.keySet();
System.out.println(set1.getClass());
Collection values = map.values();
System.out.println(values.getClass());
}
}
class Car{
}
class Person{
}
HashMap 底层机制及源码剖析
代码演示
package com.hspedu.map_;
import java.util.HashMap;
/**
* @ClassName HashMapSource1
* @Description TODO
* @Author lmy
* @Date 2022/6/16 16:49
**/
@SuppressWarnings({"all"})
public class HashMapSource1 {
public static void main(String[] args) {
HashMap map=new HashMap();
map.put("java",10); //ok
map.put("php",10); //ok
map.put("java",20); //替换value
System.out.println("map="+map);
//老韩解读HashMap的源码+图解
/**
* 1. 执行构造器 new HashMap()
* 初始化加载因子 loadfactor=0.75
* HashMap$Node[] table=null
* 2. 执行put 回调hash方法 计算key的hash值(h = key.hashCode()) ^ (h >>> 16)
* public V put(K key, V value) { //key="java" value=10
* return putVal(hash(key), key, value, false, true);
* }
* 3.执行putVal
* final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
* boolean evict) {
* Node<K,V>[] tab; Node<K,V> p; int n, i; //辅助变量
* //如果底层的 table数组为null 或者length=0 就扩容到16
* if ((tab = table) == null || (n = tab.length) == 0)
* n = (tab = resize()).length;
* //取出hash值对应的table索引位置的Node 如果为null 就直接把加入的key value
* //创建成一个Node 加入该位置即可
* if ((p = tab[i = (n - 1) & hash]) == null)
* tab[i] = newNode(hash, key, value, null);
* else {
* Node<K,V> e; K k; //辅助变量
* if (p.hash == hash &&
* //如果table的索引位置的key的hash相同和新的key的hash值相同
* //并且满足(table表中存在的结点的key和准备添加的key是同一个对象 || equals返回真)
* //就认为不能加入新的k-v
* ((k = p.key) == key || (key != null && key.equals(k))))
* e = p;
* else if (p instanceof TreeNode) //如果当前的table的已有的Node是红黑树 就按照红黑树的方式处理
* e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
* else {
* //如果找到的结点 后面是链表 就循环的比较
* for (int binCount = 0; ; ++binCount) { //死循环
* if ((e = p.next) == null) { //如果整个链表 没有找到和他相同的
* p.next = newNode(hash, key, value, null); //就加到该链表的最后
* //加入后 判断当前链表的个数 是否已经到8个 到8个 后
* //就调用treeifyBin() 方法进行红黑树的转换
* if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
* treeifyBin(tab, hash);
* break;
* }
* if (e.hash == hash && //如果在循环比较过程中 发现有相同的 就break 就只是替换vulue
* ((k = e.key) == key || (key != null && key.equals(k))))
* break;
* p = e;
* }
* }
* if (e != null) { // existing mapping for key
* V oldValue = e.value;
* if (!onlyIfAbsent || oldValue == null)
* e.value = value; //替换 key对应的值
* afterNodeAccess(e);
* return oldValue;
* }
* }
* ++modCount; //每增加一个Node 就size++
* if (++size > threshold) //如果size> 临界值 就扩容 例如16的临界值=16*0.75=12
* resize();
* afterNodeInsertion(evict);
* return null;
* }
*
* 5.关于树化(转成红黑树)
* //如果table 为null 或者大小还没有到64 暂时不树化 而是进行扩容
* //否则才会真正的树化 -> 剪枝
* final void treeifyBin(Node<K,V>[] tab, int hash) {
* int n, index; Node<K,V> e;
* if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
* resize();
* }
*/
}
}
package com.hspedu.map_;
import java.util.HashMap;
import java.util.Objects;
/**
* @ClassName HashMapSource2
* @Description TODO
* @Author lmy
* @Date 2022/6/17 07:47
**/
@SuppressWarnings({"all"})
public class HashMapSource2 {
public static void main(String[] args) {
HashMap hashMap=new HashMap();
for (int i = 1; i <= 12; i++) {
hashMap.put(new A(i),"hello");
}
hashMap.put("aaa", "bbb");
System.out.println("hashMap="+hashMap); //12个k-v
//布置一个任务,自己设计代码去验证,table 的扩容
//0 -> 16(12) -> 32(24) -> 64(64*0.75=48)-> 128 (96) ->
//自己设计程序,验证-》 增强自己阅读源码能力. 看别人代码.
}
}
class A{
private int num;
public A(int num) {
this.num = num;
}
// @Override
// public int hashCode() {
// return 100;
// }
@Override
public String toString() {
return "\nA{" +
"num=" + num +
'}';
}
}
Map 接口实现类-Hashtable
HashTable 的基本介绍
代码演示
package com.hspedu.map_;
import java.util.Hashtable;
/**
* @ClassName HashTableExercise
* @Description TODO
* @Author lmy
* @Date 2022/6/17 08:56
**/
public class HashTableExercise {
public static void main(String[] args) {
Hashtable table = new Hashtable(); //ok
table.put("join",100); //ok
// table.put(null,100); 异常 NullPointerException
// table.put("john",null) ; 异常 NullPointerException
table.put("lucy",100); //ok
table.put("lic",100); //ok
table.put("lic",88); //替换
table.put("hello1",1);
table.put("hello2",1);
table.put("hello3",1);
table.put("hello4",1);
table.put("hello5",1);
table.put("hello6",1);
System.out.println(table);
//简单说明一下HashTable的底层
//1.底层有数组 Hashtable$Entry[] 初始化大小为11
//2.临界值 threshold 8=11*0.75
//3.扩容: 按照自己的扩容机制来进行即可
//4.执行 方法 addEntry(hash, key, value, index); //添加k-v 封装到Entry
//5. 当 if (count >= threshold) 满足时,就进行扩容
//5. 按照 int newCapacity = (oldCapacity << 1) + 1; 的大小扩容.
}
}
Hashtable 和 HashMap 对比
Map 接口实现类-Properties
基本介绍
基本使用
代码演示
package com.hspedu.map_;
import java.util.Properties;
/**
* @ClassName Properties_
* @Description TODO
* @Author lmy
* @Date 2022/6/17 12:54
**/
@SuppressWarnings({"all"})
public class Properties_ {
public static void main(String[] args) {
//老韩解读
//1. Properties 继承 Hashtable
//2. 可以通过 k-v 存放数据 当然key 和 value 不能为null
//增加
Properties properties=new Properties();
properties.put("john",100); //k-v
properties.put("lucy",100); //k-v
properties.put("lic",100);
properties.put("lic",88); //如果有相同的key value值被替换
//properties.put(null,100); //抛出空指针异常
//properties.put("john",null); //抛出空指针异常
System.out.println("properties=" + properties);
//通过k 获取对应的值1``
System.out.println("lic对应的值是:"+properties.get("lic")); //88
//删除
System.out.println("删除后的集合:");
properties.remove("lic");
System.out.println("properties=" + properties);
//修改
System.out.println("修改后的集合");
properties.put("john","约翰");
System.out.println("properties=" + properties);
}
}
总结-开发中如何选择集合实现类(记住)
TreeSet
代码演示
package com.hspedu.set_;
import java.util.Comparator;
import java.util.TreeSet;
/**
* @ClassName TreeSet_
* @Description TODO
* @Author lmy
* @Date 2022/6/17 16:39
**/
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
//老韩解读
//1.当我们使用无参构造器 创建TreeSet时 仍然是无序的
//2.老师希望添加的元素 按照字符串大小来排序
//3.使用TreeSet 提供的一个构造器 可以传入一个比较器(匿名内部类)
// 并指定排序规则
//4.简单看看源码
//TreeSet treeSet=new TreeSet();
TreeSet treeSet=new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//下面 调用String的 compareTo 方法进行字符串大小比较
//下面老韩要求加入的元素 按照长度大小排序
return ((String)o1).compareTo((String)o2); //字符串大小比较
//如果有长度相同的则只会输出第一个 其余的都不会输出
//return ((String)o2).length()-((String)o1).length(); //长度大小排序 (大-小) treeSet=[jack, tom, sp, a]
//return ((String)o1).length()-((String)o2).length(); //长度大小排序 (小-大) treeSet=[a, sp, tom, jack]
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom"); //3
treeSet.add("sp");
treeSet.add("a");
treeSet.add("abc"); //3
System.out.println("treeSet=" + treeSet);
//老韩源码解读
/**
* 1.构造器把传入的比较器对象 赋给了TreeSet的底层的TreeMap的this.comparator
* public TreeMap(Comparator<? super K> comparator) {
* this.comparator = comparator;
* }
* 2.在调用treeSet.add("tom") 在底层会执行到
* if (cpr != null) { //cpr就是我们的匿名内部类(对象)
* do {
* parent = t;
* cmp = cpr.compare(key, t.key); //动态绑定到我们的匿名内部类(对象)compare
* if (cmp < 0)
* t = t.left;
* else if (cmp > 0)
* t = t.right;
* else //如果相等 即返回0 这个Key就没有加入
* return t.setValue(value);
* } while (t != null);
* }
*/
}
}
TreeMap
代码演示
package com.hspedu.map_;
import java.util.Comparator;
import java.util.TreeMap;
/**
* @ClassName TreeMap_
* @Description TODO
* @Author lmy
* @Date 2022/6/17 17:25
**/
@SuppressWarnings({"all"})
public class TreeMap_ {
public static void main(String[] args) {
//使用默认的构造器 创建TreeMap 是无序的
/**
* 老韩要求: 要求按照传入的 k(String) 的大小进行排序
*/
//TreeMap treeMap = new TreeMap();
TreeMap treeMap=new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//按照传入的 k(String) 的大小进行排序 小-大 treemap={jack=杰克, kristina=克瑞斯提诺, smith=史密斯, tom=汤姆}
return ((String)o1).compareTo((String)o2);
//按照传入的 k(String) 的大小进行排序 大-小 treemap={tom=汤姆, smith=史密斯, kristina=克瑞斯提诺, jack=杰克}
//return ((String)o2).compareTo((String)o1);
//如果有长度相同的则只会输出第一个 其余的都不会输出
//长度大小排序 (小-大) treemap={tom=汤姆, jack=杰克, smith=史密斯, kristina=克瑞斯提诺}
//return ((String)o1).length()-((String)o2).length();
//长度大小排序 (大-小) treemap={kristina=克瑞斯提诺, smith=史密斯, jack=杰克, tom=汤姆}
//return ((String)o2).length()-((String)o1).length();
}
});
treeMap.put("jack","杰克");
treeMap.put("tom","汤姆");
treeMap.put("kristina","克瑞斯提诺");
treeMap.put("smith","史密斯");
treeMap.put("hsp","韩顺平"); //加入不了
System.out.println("treemap="+treeMap);
//老韩源码解读
/**
*1.构造器 把传入的实现了 Comparator接口的匿名内部类(对象) 传给了TreeMap的comparetor
* public TreeMap(Comparator<? super K> comparator) {
* this.comparator = comparator;
* }
*2.调用put方法
*2.1第一次添加 把k-v 封装到 Entry对象 放入root
* Entry<K,V> t = root;
* if (t == null) {
* compare(key, key); // type (and possibly null) check
*
* root = new Entry<>(key, value, null);
* size = 1;
* modCount++;
* return null;
* }
* 2.2 以后添加
* Comparator<? super K> cpr = comparator;
* if (cpr != null) {
* do { //遍历所有的key 给当前key找到适当位置
* parent = t;
* cmp = cpr.compare(key, t.key); //动态绑定到我们的匿名内部类的compare
* if (cmp < 0)
* t = t.left;
* else if (cmp > 0)
* t = t.right;
* else //如果遍历过程中 发现准备添加Key 和当前已有的Key 相等 就不添加
* return t.setValue(value);
* } while (t != null);
* }
*/
}
}
Collections 工具类
Collections 工具类介绍
排序操作:(均为 static 方法)
代码演示
package com.hspedu.collections_;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @ClassName Collections
* @Description TODO
* @Author lmy
* @Date 2022/6/17 19:26
**/
public class Collections_ {
public static void main(String[] args) {
//创建ArrayList 集合 用于测试
List list=new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
//reverse(list) 反转List集合元素进行随机排序
Collections.reverse(list);
System.out.println("反转排序后:" + list);
//shuffle(list) 对List集合元素进行随机排序
Collections.shuffle(list);
System.out.println("随机排序后:" + list);
//sort(list): 根据元素的自然顺序对指定List集合元素按升序排序
Collections.sort(list);
System.out.println("自然排序后:" + list);
//sort(list,Comparator):根据指定的Comparator 产生的顺序对List集合元素进行排序
//我们希望按照字符串的长度大小排序
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//可以加入校验
//return ((String)o1).length()-((String)o2).length(); //小-大
return ((String)o2).length()-((String)o1).length(); //大-小
}
});
System.out.println("字符串长度大小排序后:" + list);
//swap(List,int,int) 将指定List集合中的i处元素和j处元素进行交换
Collections.swap(list,0,1);
System.out.println("指定位置交换排序后:" + list);
}
}
查找、替换
代码演示
//Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
System.out.println("自然顺序最大元素=" + Collections.max(list));
//Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
//比如,我们要返回长度最大的元素
Object maxObject = Collections.max(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
System.out.println("长度最大的元素=" + maxObject);
//Object min(Collection)
//Object min(Collection,Comparator)
//上面的两个方法,参考max即可
//int frequency(Collection,Object):返回指定集合中指定元素的出现次数
System.out.println("tom出现的次数=" + Collections.frequency(list, "tom"));
//void copy(List dest,List src):将src中的内容复制到dest中
ArrayList dest = new ArrayList();
//为了完成一个完整拷贝,我们需要先给dest 赋值,大小和list.size()一样
for(int i = 0; i < list.size(); i++) {
dest.add("");
}
//拷贝
Collections.copy(dest, list);
System.out.println("dest=" + dest);
//boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
//如果list中,有tom 就替换成 汤姆
Collections.replaceAll(list, "tom", "汤姆");
System.out.println("list替换后=" + list);
本
本章作业
代码演示1
package com.hspedu.homework;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
/**
* @ClassName Homework01
* @Description TODO
* @Author lmy
* @Date 2022/6/17 19:57
**/
/**
* 按要求实现:
* (1) 封装一个新闻类,包含标题和内容属性,提供get、set方法,重写toString方法,打印对象时只打印标题;
* (2) 只提供一个带参数的构造器,实例化对象时,只初始化标题;并且实例化两个对象:
* 新闻一:新冠确诊病例超千万,数百万印度教信徒赴恒河“圣浴”引民众担忧
* 新闻二:男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生
* (3) 将新闻对象添加到ArrayList集合中,并且进行倒序遍历;
* (4) 在遍历集合过程中,对新闻标题进行处理,超过15字的只保留前15个,然后在后边加“…”
* (5) 在控制台打印遍历出经过处理的新闻标题;
*/
public class Homework01 {
public static void main(String[] args) {
ArrayList arrayList=new ArrayList();
arrayList.add(new News("新冠确诊病例超千万,数百万印度教信徒赴恒河'圣浴'引民众担忧"));
arrayList.add(new News("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生"));
int size=arrayList.size();
for(int i=size-1;i>=0;i--){
// System.out.println(arrayList.get(i));
News news=(News)arrayList.get(i);
System.out.println(processTitle(news.getTitle()));
}
}
//专门写一个方法 处理显示新闻标题 process处理
public static String processTitle(String title) {
if(title == null) {
return "";
}
if(title.length() > 15) {
return title.substring(0, 15) + "..."; //[0,15)
} else {
return title;
}
}
}
class News{
private String title; //标题
private String content; //内容
public News(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "News{" +
"title='" + title + '\'' +
'}';
}
}
代码演示2
package com.hspedu.homework;
/**
* @ClassName Homework02
* @Description TODO
* @Author lmy
* @Date 2022/6/17 20:16
**/
import java.util.ArrayList;
import java.util.Iterator;
/**
* 使用ArrayList 完成对 对象 Car {name, price} 的各种操作
* 1.add:添加单个元素
* 2.remove:删除指定元素
* 3.contains:查找元素是否存在
* 4.size:获取元素个数
* 5.isEmpty:判断是否为空
* 6.clear:清空
* 7.addAll:添加多个元素
* 8.containsAll:查找多个元素是否都存在
* 9.removeAll:删除多个元素
* 使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法
*/
public class Homework02 {
public static void main(String[] args) {
ArrayList arrayList=new ArrayList();
Car car1=new Car("宝马",400000.0);
Car car2=new Car("宾利",5000000.0);
//1.add:添加单个元素
arrayList.add(car1);
arrayList.add(car2);
System.out.println(arrayList);
//2.remove:删除指定元素
arrayList.remove(0);
System.out.println(arrayList);
//3.contains:查找元素是否存在
System.out.println(arrayList.contains(car1));
//4.size:获取元素个数
System.out.println(arrayList.size());
//5.isEmpty:判断是否为空
System.out.println(arrayList.isEmpty());
//6.clear:清空
// arrayList.clear();
System.out.println(arrayList);
//7.addAll:添加多个元素
arrayList.addAll(arrayList);
System.out.println(arrayList);
//8.containsAll:查找多个元素是否都存在
arrayList.containsAll(arrayList);
System.out.println(arrayList);
//9.removeAll:删除多个元素
//arrayList.removeAll(arrayList); 清空
System.out.println(arrayList);
//使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法
//增强for
System.out.println("增强for循环遍历:");
for (Object obj : arrayList) {
System.out.println(obj);
}
//迭代器
System.out.println("迭代器遍历:");
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
}
}
class Car{
private String name;
private Double price;
public Car(String name, Double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
代码演示3
package com.hspedu.homework;
/**
* @ClassName Homework03
* @Description TODO
* @Author lmy
* @Date 2022/6/17 20:40
**/
import java.util.*;
/**
* 按要求完成下列任务
* 1)使用HashMap类实例化一个Map类型的对象m,键(String)和值(int)分别用于存储员工的姓名和工资,
* 存入数据如下: jack—650元;tom—1200元;smith——2900元;
* 2)将jack的工资更改为2600元
* 3)为所有员工工资加薪100元;
* 4)遍历集合中所有的员工
* 5)遍历集合中所有的工资
*/
public class Homework03 {
public static void main(String[] args) {
//1.使用HashMap类实例化一个Map类型的对象m,键(String)和值(int)分别用于存储员工的姓名和工资,存入数据如下:
//jack—650元;tom—1200元;smith——2900元;
HashMap m=new HashMap();
m.put("jack",650);
m.put("tom",1200);
m.put("smith",2900);
System.out.println(m);
//2.将jack的工资更改为2600元
m.put("jack",2600);
System.out.println(m);
//3.为所有员工工资加薪100元;
//keySet
Set set = m.keySet();
for (Object key : set) {
//更新
m.put(key,(Integer)m.get(key)+100);
}
System.out.println(m);
System.out.println("=============遍历=============");
//4.遍历集合中所有的员工
//遍历 EntrySet
Set entrySet = m.entrySet();
//迭代器
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry)iterator.next();
System.out.println(entry.getKey() + "-" + entry.getValue());
}
//5.遍历集合中所有的工资
System.out.println("====遍历所有的工资====");
Collection values = m.values();
for (Object value : values) {
System.out.println("工资=" + value);
}
}
}
代码演示4
package com.hspedu.homework;
import java.util.TreeSet;
/**
* @author 韩顺平
* @version 1.0
*/
@SuppressWarnings({"all"})
public class Homework04 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
treeSet.add("hsp");
treeSet.add("tom");
treeSet.add("king");
treeSet.add("hsp");//加入不了
System.out.println(treeSet);
}
}
代码演示5
package com.hspedu.homework;
import java.util.TreeSet;
//
//import java.util.TreeSet;
//
///**
// * @author 韩顺平
// * @version 1.0
// */
@SuppressWarnings({"all"})
public class Homework05 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
//分析源码
//add 方法,因为 TreeSet() 构造器没有传入Comparator接口的匿名内部类
//所以在底层 Comparable<? super K> k = (Comparable<? super K>) key;
//即 把 Perosn转成 Comparable类型
treeSet.add(new Person());//ClassCastException.
treeSet.add(new Person());//ClassCastException.
treeSet.add(new Person());//ClassCastException.
treeSet.add(new Person());//ClassCastException.
treeSet.add(new Person());//ClassCastException.
System.out.println(treeSet);
}
}
class Person implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
代码演示6
package com.hspedu.homework;
import java.util.HashSet;
import java.util.Objects;
/**
* @author 韩顺平
* @version 1.0
*/
@SuppressWarnings({"all"})
public class Homework06 {
public static void main(String[] args) {
HashSet set = new HashSet();//ok
Person p1 = new Person(1001,"AA");//ok
Person p2 = new Person(1002,"BB");//ok
set.add(p1);//ok
set.add(p2);//ok
p1.name = "CC";
set.remove(p1);
System.out.println(set);//2
set.add(new Person(1001,"CC"));
System.out.println(set);//3
set.add(new Person(1001,"AA"));
System.out.println(set);//4
}
}
class Person {
public String name;
public int id;
public Person(int id, String name) {
this.name = name;
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, id);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}