对于HashMap中equals和Hashcode的重写及理解

原创不易,转载请注明出处https://blog.csdn.net/weixin_43330377/article/details/109706045

今天写完了实验四Java集合与泛型的实验报告,发现自己对HashMap中equals和Hashcode理解不深,因此查阅资料后做出如下总结,以及在实验过程中出现的问题。

加深印象,便于复习

【实验总结】

  • 1.关于java中的三大容器List、Map、Set的详解不加以叙述。
    但要注意的是,List有Index索引,Map有Key键,根据index和Key的不同,同一个对象或者Value可以存放在不同的位置(有序),但Set由于没有相应的唯一标识,故不准许添加相同的内容(无序:通过equals和Hashcode进行判断,同时相等,则判定为相同对象,若不同,则判定为不同的对象。)。

equals和Hashcode方法及重写的理解与总结

  • 2.“由Teacher可以根据id比大小”引发的对于equals和Hashcode方法及重写的理解与总结

(1)思路:由于HashMap根据Key的HashCode进行排序返回,我们可以根据当equals()都返回True时,根据Key中Teacher 类ID的HashCode的不同进行区分排序。
(2)代码如下:

 @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Teacher)) return false;
        Teacher teacher = (Teacher) o;
        return getId() == teacher.getId();

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

(3)注意事项!!!!!
判断相等的过程是:先判断两个对象的HashCode的值是否相等,若相等,再进行equals()判断。若HashCode不相等,则判断两个对象不相等,直接加入到容器中,不再进行equals()比较。

两个方法必须同时重写
如果仅重写HashCode,系统调用的是Object 类中的equals()方法,直接调用“==”,比较的是对象的内存地址。
源码如下:

public boolean equals(Object obj) {
        return (this == obj);
    }

当我们用new创建的对象和数组的时候,尽管内容完全一样,但其相应的堆内存却不同
如: teacher1 teacher2尽管完全相同,但返回的地址却不同。

  Teacher teacher1=new Teacher("罗老师",001,"C++","Java");
   Teacher teacher2=new Teacher("罗老师",001,"C++","Java");

因为重写了HashCode,所以他们的HashCode的值相同,但equals却返回false,会发生Hash碰撞,也就是两个不同对象的HashCode相同,Hashmap会试图把他们保存在同一个位置,又无法成功。就会在相应位置用链式结构保存多个对象,通过遍历链表进行equals()最终找到要找的值对象。
不但违背了Set容器的规则,而且又使性能下降。

如果仅仅重写equals(),系统调用的是Object 类中的HashCode()方法,hashCode返回的是由对象存储地址转化得到的值。
上述例子已经表明相同内容不同对象返回的地址不同,所以通常情况下HashCode不同,则不会继续进行equals的判断,直接将元素加入到相应位置中,违背了Set容器的规范。(编译运行不会报错。)
注:当返回的hash码产生溢出时,也可能会出现不同对象hashcode相同的情况

  • 3.indexof():查找一个字符串中,首次出现该字符串位置的索引,若没有出现则返回-1。
    get():List中的第i+1(对应的索引值)个对象
    最开始的时候我将这两个方法混淆,用Indexof(Index)找对象,结果都返回为-1,表明该对象不存在。
    因此若对象明明存在ArrayList中却依旧返回-1,可能是Indexof()方法使用错误。
  • 4.错误:Operator ‘+’ cannot be applied to ’ ', ’ ’
    解决办法: 两个对象之间加个分隔符就好了。
  • 5 .ArrayList是在第一次添加元素时容量扩大至 10 的,故说其初始容量为10。当超过容量时,可以动态扩容。

附:【实验内容】

定义类 Teacher
属性:
String name;
int id;
String cpp;( 教授课程1)
String java; ( 教授课程2)
方法:根据需要自定。
所有集合要求用泛型
1、编写程序练习List集合的基本使用:
(1) 创建一个只能容纳Teacher类型的对象的ArrayList集合;
(2) 按顺序往集合中添加5个Teacher对象;
(3) 对集合进行遍历,分别打印集合中的每个元素的位置与内容;
(4) 首先打印集合的大小,然后删除集合中的第3个元素,并显示删除元素的内容,再次打印集合的大小。
2、编写程序练习Map集合的基本使用:
(1) 创建一个HashMap集合,要求以Teacher作为键(Teacher可以根据id比大小),同样以Teacher作为值;
(2) 往集合中添加5个“键-值”对象;
(3) 对集合进行遍历,分别打印集合中的每个元素的键与值;
(4) 获得集合中的所有键的集合,并进遍历;
(5) 用entrySet获取键值对,并进行遍历。
(6) 练习使用Map.Entry,自己写一个测试。

【实验代码】

Teacher .java

import java.util.Objects;

public class Teacher {
    String  name;
    int id;
    String  cpp;//( 教授课程1)
    String  java; //( 教授课程2)
    public Teacher(String name, int id, String cpp, String java) {
        this.name = name;
        this.id = id;
        this.cpp = cpp;
        this.java = java;
    }

    public int getId() {
        return id;
    }
    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", cpp='" + cpp + '\'' +
                ", java='" + java + '\'' +
                '}';
    }//根据ID打印
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Teacher)) return false;
        Teacher teacher = (Teacher) o;
        return getId() == teacher.getId();

    }

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

TeacherTest1.java(List)


import java.util.ArrayList;
import java.util.List;
public class TeacherTest1 {

    public static void main(String[] args) {

       /* 创建一个只能容纳Teacher类型的对象的ArrayList集合;*/
        List<Teacher> teacherList= new ArrayList();
        Teacher teacher1=new Teacher("罗老师",001,"C++","Java");
        Teacher teacher2=new Teacher("宋老师",002,"计算机组成原理","单片机");
        Teacher teacher3=new Teacher("张老师",003,"操作系统","软件测试");
        Teacher teacher4=new Teacher("吴老师",004,"数据库原理","SQL");
        Teacher teacher5=new Teacher("邓老师",005,"信息系统分析与设计","软件工程");

        /*	按顺序往集合中添加5个Teacher对象;*/
        teacherList.add(0,teacher1);
        teacherList.add(1,teacher2);
        teacherList.add(2,teacher3);
        teacherList.add(3,teacher4);
        teacherList.add(4,teacher5);
    /*对集合进行遍历,分别打印集合中的每个元素的位置与内容; */
       /*lambda表达式*/
        System.out.println("---------------------------");
        teacherList.forEach((i)-> {
            System.out.println("元素:"+i);
                System.out.println("位置:"+teacherList.indexOf(i));
                });
        System.out.println("---------------------------");

        /*首先打印集合的大小,然后删除集合中的第3个元素,并显示删除元素的内容,再次打印集合的大小。*/

            System.out.println("删除前集合的大小为:"+teacherList.size());
        System.out.println("被删除的元素为:"+teacherList.get(2) );
        //注意这俩放的位置,否则会打印出被删除后相应位置的索引内容
            teacherList.remove( 2);
        //indexof里面是对象而不是int!!!!!!!!
        //indexOf()是在ArrayList中查找某个数据出现的位置索引,如果在ArrayList中没有找到这个数据,就会返回-1
            System.out.println("删除后集合的大小为:"+teacherList.size());
    }
}


TeacherTest2.java(Map)



import java.util.*;

public  class TeacherTest2   {
    public static void main(String[] args) {

        System.out.println("--------以下为根据ID排序--------");
        /* 创建一个HashMap集合,要求以Teacher作为键(Teacher可以根据id比大小),同样以Teacher作为值*/
        Map<Teacher, Teacher> teacherHMap = new HashMap();


        /*往集合中添加5个“键-值”对象;对集合进行遍历,分别打印集合中的每个元素的键与值*/

        Teacher teacher1 = new Teacher("罗老师", 1, "C++", "Java");
        Teacher teacher2 = new Teacher("宋老师", 2, "计算机组成原理", "单片机");
        Teacher teacher3 = new Teacher("张老师", 3, "操作系统", "软件测试");
        Teacher teacher4 = new Teacher("吴老师", 4, "数据库原理", "SQL");
        Teacher teacher5 = new Teacher("邓老师", 5, "信息系统分析与设计", "软件工程");
        Teacher teacher6 = new Teacher("22", 9, "信息系统分析与设计", "软件工程");

        teacherHMap.put(teacher6, teacher1);
        teacherHMap.put(teacher2, teacher2);
        teacherHMap.put(teacher3, teacher3);
        teacherHMap.put(teacher4, teacher4);
        teacherHMap.put(teacher5, teacher5);



        /*为什么是这个打印顺序?
        Map根据键的HashCode值存储数据, 
        */
        System.out.println("-------------------往集合中添加5个“键-值”对象;对集合进行遍历,分别打印集合中的每个元素的键与值------------------------");

        teacherHMap.forEach((k, v) -> {
            System.out.println("键:" + k);
            System.out.println("值:" + v);
            System.out.println("-------------------------------------------");
        });



        /*获得集合中的所有键的集合,并进遍历*/
        System.out.println("-------获得集合中的所有键的集合,并进遍历--------");

        teacherHMap.keySet().forEach((key)-> {
                    System.out.println("键:" + key);


        });
            /*用entrySet获取键值对,并进行遍历*/
        System.out.println("-------用entrySet获取键值对,并进行遍历11-------");
        teacherHMap.entrySet().forEach((key)-> {
            System.out.println("键值对:" + key);

        });
     
        System.out.println("-------练习使用Map.Entry,自己写一个测试111-------");

        for(Map.Entry<Teacher,Teacher> e:teacherHMap.entrySet()){
            Teacher key=e.getKey();
            Teacher value=e.getValue();
            System.out.println(key+":"+value);
        }

        System.out.println("-------练习使用Map.Entry,自己写一个测试222-------");
        /*	练习使用Map.Entry,自己写一个测试*/
        /*Iterator是一个接口,它是集合的迭代器。集合可以通过Iterator去遍历集合中的元素*/
        Iterator<Map.Entry<Teacher, Teacher>> it=teacherHMap.entrySet().iterator();
        while(it.hasNext()) {
            Map.Entry<Teacher,Teacher> entry=it.next();/*next():返回迭代器中的下一个元素*/
            Teacher key=entry.getKey();
           Teacher value=entry.getValue();
            System.out.println(key+"\n"+value+"\n");
         //   Operator '+' cannot be applied to 'Teacher', 'Teache
            //解决办法,值中间加个”“
        }
 }
}

【 实验结果】

TeacherTest1.java(List)
在这里插入图片描述
TeacherTest2.java(Map)
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值