首页 > 编程语言 >day22--Java集合05

day22--Java集合05

时间:2022-08-17 19:24:02浏览次数:48  
标签:return name 05 -- new Employee Java public String

Java集合05

11.HashSet课堂练习

11.1课堂练习1

定义一个Employee类,该类包括:private成员属性name,age

要求:

  1. 创建3个Employee对象放入HashSet中
  2. 当name和age的值相同时,认为是相同员工,不能添加到HashSet集合中

思路:不同对象的哈希值一般会不一样,导致在添加对象时可能会在table数组的不同位置添加,因此想要比较对象的属性值,就要重写hashCode方法,使具有相同属性的对象具有一样的hash值,这样才能在插入时比较对象的值;但不同的对象也可能具有相同的hash值,所以要重写equals方法来比较对象属性值

如下图:在add()方法最终调用的putVal()方法中可以看出,如果插入的新元素的哈希值相同 且 值也相同 就不加入

image-20220817173700933

例子:

package li.collections.set.hashset;

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

@SuppressWarnings("all")
public class HashSetPractice {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee("jack", 18));
        hashSet.add(new Employee("smith", 18));
        hashSet.add(new Employee("jack", 18));

        System.out.println(hashSet);//[Employee{name='smith', age=18.0}, Employee{name='jack', age=18.0}]

    }
}

class Employee {
    private String name;
    private double age;

    public Employee(String name, double age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public double getAge() {
        return age;
    }

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

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

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

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

image-20220817145110916

快捷键:alt+insert选择equals()and hashCode()快速重写

image-20220817144139231

如果name和age的值相同,在使用equals时,返回true

image-20220817142610039

如果name和age的值相同,在计算hashCode的时候返回相同的hash值

image-20220817142652561

11.2课堂练习2

定义一个Employee类,该类包含:private成员属性name,sal,birthday,其中birthday为MyDate类型,属性包括year,month,day

要求:

  1. 创建3个Employee对象放入到HashSet中
  2. 当name和birthday的值相同时,热卫视相同员工,不能添加到HashSet集合中

思路:和练习1思路一致,不同的是MyDate类也要重写equals()和hashCode()方法

练习:

package li.collections.set.hashset;

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

@SuppressWarnings("all")
public class HashSetPractice2 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee("jack",8000,new MyDate(1997,12,23)));
        hashSet.add(new Employee("jack",8000,new MyDate(1997,12,23)));
        hashSet.add(new Employee("jack",8000,new MyDate(1997,12,23)));
        hashSet.add(new Employee("jack",8000,new MyDate(1997,12,23)));

        System.out.println(hashSet);//[Employee{name='jack', sal=8000.0, birthday=MyDate{year=1997, month=12, day=23}}]

    }
}

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

    public Employee(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;
        Employee employee = (Employee) o;
        return Double.compare(employee.sal, sal) == 0 && Objects.equals(name, employee.name) && Objects.equals(birthday, employee.birthday);
    }

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

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


class MyDate {
    private int year;
    private int month;
    private int day;

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

    public int getYear() {
        return year;
    }

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

    public int getMonth() {
        return month;
    }

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

    public int getDay() {
        return day;
    }

    public void setDay(int 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 year == myDate.year && month == myDate.month && 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 +
                '}';
    }
}

image-20220817151236874

12.LinkedHashSet

12.1LinkedHashSet底层

  1. LinkedHashSet是HashSet的子类
  2. LinkedHashSet底层是一个LinkedHashMap(LinkedHashMap是HashMap的子类),底层维护了一个 数组+双向链表
  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也能确保插入顺序和遍历顺序一致

例子1:LinkedHashSet底层分析

package li.collections.set.hashset;

import java.util.LinkedHashSet;
import java.util.Set;

@SuppressWarnings("all")

public class LinkedHashSetSource {
    public static void main(String[] args) {
        Set set = new LinkedHashSet();
        set.add(new String("AA"));
        set.add(456);
        set.add(456);
        set.add(new Customer("刘", 1001));
        set.add(123);
        set.add("jack");
        System.out.println(set);
    }
}

class Customer {
    private String name;
    private int number;

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

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

如下图,LinkedHashSet不允许重复值,且插入顺序和取出顺序一致

image-20220817162824487

Set set = new LinkedHashSet();出打上断点调试:

如下图:可以看到,LinkedHashSet底层是一个LinkedHashMap

image-20220817162353027

如下图所示:点击map展开,Step Over之后可以看到第一次添加数据时,直接将数组table扩容到16(数组下标从零开始),存放的节点类型是LinkedHashMap$Entry

数组是HashMap$Node[ ]

存放的元素/数据是LinkedHashMap$Entry类型(LinkedHashMap的内部类Entry继承了HashMap的内部类Node)

image-20220817163548224 image-20220817163414758

image-20220817165732968

如下图:继续添加数据,可以看到在索引为8 的位置添加了新的数据456,点开索引为0 的节点,可以看到这时原来节点的after指向了新的节点,并且新结点的before指向了原来的节点,形成了双向链表

image-20220817170428965 image-20220817170406668

如下图所示:在add()底层仍然是和HashSet调用了相同的方法,详情见10.3HashSet源码详解

image-20220817171558864

image-20220817171651392

image-20220817171818571

以此类推,形成一条双向链表:

image-20220817172328474

12.1.LinkedHashSet练习

有一个Car类,存在两个私有属性name和price

要求:如果两个Car对象的name和price一样,就认为是相同元素,不能添加

练习:

package li.collections.set.hashset;

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

@SuppressWarnings("all")
public class LinkedHashSetPractice {
    public static void main(String[] args) {
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        linkedHashSet.add(new Car("奥拓",100_000));
        linkedHashSet.add(new Car("保时捷",990_000));
        linkedHashSet.add(new Car("法拉利",3100_000));
        linkedHashSet.add(new Car("特斯拉",100_000));
        linkedHashSet.add(new Car("特斯拉",100_000));
        for (Object o:linkedHashSet) {
            System.out.println(o);
        }
    }
}

class Car{
    private String name;
    private double price;

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

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

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

在没有重写hashCode()和equals()之前不同的对象实例的hash值一般是不一样的,因此可以插入name和price相同的对象数据。重写之后可以看到相同属性的对象无法插入了。具体解题思路和11HashSet的课堂练习一致。

13.Map接口

image-20220817180129001

13.1Map接口特点

Map接口实现类的特点:( JDK8的Map接口特点 )

  1. Map和Collection并列存在。Map用于保存具有映射关系的数据:key-value(双列元素)
  2. Map中的key和value可以是任何引用类的数据,会封装到HashMap$Node对象中
  3. Map中的key不允许重复(key值不允许重复,重复的话就会用新的值替换/覆盖旧的值e = p--->详细原因和HashSet一样,详见10.1-10.3)
  4. Map中的value允许重复(hash值取决于key)
  5. Map中的key可以为null,value也可以为null(注意key的null最多只能有一个,value的null可以有多个)
  6. 常用String类作为Map的key
  7. key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value

例子:map的简单使用

package li.map;

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

public class MapIntroduce {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("no1","北京");//k-v
        map.put("no4","深圳");//k-v
        map.put("no4","长沙");//no4=长沙-->key值不允许重复,重复的话就会用新的值替换/覆盖旧的值 e=p
        map.put("no5","北京");//value可以重复,hash值取决于key
        map.put(null,null);
        map.put(null,"abc");//key不能重复,因此这里的值会将上一行的值覆盖 null=abc
        map.put("abc",null);//value可以重复
        map.put(new Object(),123);

        //无序的:原因是底层是按计算的hash值来存放
        //{null=abc, no1=北京, no4=长沙, abc=null, no5=北京, java.lang.Object@1b6d3586=123}
        System.out.println(map);

        //通过指定的key总能找到对应的value
        System.out.println(map.get(null));//abc
        System.out.println(map.get("no1"));


    }

}

标签:return,name,05,--,new,Employee,Java,public,String
From: https://www.cnblogs.com/liyuelian/p/16596482.html

相关文章

  • 存储过程和函数(自定义函数)
    储存过程和函数:存储过程:         分类:1.存储过程的参数类型可以是IN、OUT和INOUT。根据这点分类如下:             ......
  • 前端请求不到数据_后端写代码直接复制_部分内容没有修改
    ......
  • computed
    computed参考自:https://v2.cn.vuejs.org/v2/api/#computedcomputed与watch的区别:http://t.zoukankan.com/jing-tian-p-11247546.htmlcomputed:{//仅读取double......
  • 摸鱼系列之idea摸鱼插件推荐
    前言作为一枚程序员,上班时候正撸着代码呢,撸不出代码了,没灵感了,看需求念头不通达了,脑瓜里蹦不出一丁点火花了,这时候怎么办?程序在运行,还要好几分钟,等待时间里,白白浪费了,玩......
  • 学习:python 模块
    模块是python最高级别的组织单元将程序代码和数据封装起来以便重复使用模块中包含了实现某一类业务的多个函数和属性说的通俗点模块就是一个实现某种业务的工具包,每一......
  • 开关(线段树区间异或板子)
    [TJOI2009]开关题目描述现有\(n\)盏灯排成一排,从左到右依次编号为:\(1\),\(2\),……,\(n\)。然后依次执行\(m\)项操作。操作分为两种:指定一个区间\([a,b]\),然后改变......
  • 8.17总结
    自动刷题机\(solution\)二分答案找最大最小值考试时二分写错了ACCode#include<bits/stdc++.h>usingnamespacestd;#definelllonglonginlinellread(){ ll......
  • python 日志写入文件
    importloggingfmt="%(asctime)s%(filename)s[line:%(lineno)d]%(levelname)s:%(message)s"logging.basicConfig(level=logging.DEBUG,format=fmt,......
  • 【算法基础】旋转卡壳算法理解
    前言 参考1.旋转卡壳系列博客;2. 旋转卡壳(1)--求凸包(点集)直径poj2187;完......
  • 【python error】FutureWarning: The error_bad_lines argument has been deprecated
    前言博主运行python代码的时候出现了warning,主要是模块版本引起的。drawlog.py  warningdrawlog.py:76:FutureWarning:Theerror_bad_linesargumenthasbeend......