对象比较不相等?遍历太麻烦?超详细一个案例教你重写自定义类的equals()方法,hashCode() ,toString()!

重写自定义类的equals()方法,可以自定义对象相同的条件

为什么要重写equals() 方法?

  1. 会有判断两个元素是否相等 equals() 时找不到的问题时。
  2. 想使用系统中提供的方法更方便的写代码时。

这是因为没有重写自定义类型的equals()方法

判断两个元素是否相等 equals() 时找不到的问题时
//现在有一个Studnet类
public class Student {
    public String name;
    public int age;

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

//执行
 public static void main(String[] args) {
 		//创建两个我们自以为相同的学生对象
        Student s1 = new Student("小明", 18);  
        Student s2 = new Student("小明", 18);
        System.out.println(s1.equals(s2));  //结果为 false
    }

此时发现 结果是false ,而不是我们想象的true 为什么呢?

因为如果不重写equals() 方法,使用的是Object中的equals方法,即默认情况下会按照对象的内存地址进行比较

Student s3 = s1;
System.out.println(s1.equals(s3));  //true.
Object中的equals源码
public boolean equals(Object obj) {
        return (this == obj);
    }

这样可以看出 其实内部做对象比较的时候还是使用的 == 在比较

想使用系统提供的方法快速编写代码时

这里用List集合举例

//现有一个 学生集合 存了三个学生
List<Student> list =new ArrayList<>();
list.add(new Student("小明",18));
list.add(new Student("小红",20));
list.add(new Student("小刚",22));

此时我想添加一个学生并不想让姓名重复时我们该怎么办?

可能第一时间想到的就是遍历,

//遍历  .....  
for(Student s : list){ ... }

也可能想到了List中提供的方法 contains indexOf …

但是你突然发现,都是false ,或者就是 -1 之类的,反正就是List没有这个对象

此时因为什么?因为你的自定义类没有重写equals方法,系统默认比较对象的内存地址。

如何重写equals方法

如下 在 Student 类中

 public class Student {
 
 @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (!(o instanceof Student))
            return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
        //注意这个是Objects  不是Object  加了s的
    }
}

equals里边的内容自已设置。这里只考虑返回值

return true; 表示两个对象相同

return false; 表示两个对象不同

上图中的意思时 如果两个对象的name属性值相同就表示学生是一个学生。

上图代码中的Objects类中的静态equals方法的解释

直接看源码:

public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));  
        //使用的还是你传入对象类型的equals方法
        // 如果该类型没有重写equals方法,会上找父类的equals方法直到Object
    }

可以看出使用的还是传入对象的equals方法
此时会有同学问,a b明明是Object类型,为什么不是直接使用的是Object的equals方法而是实际对象类型的?
因为override是重写,你已经把父类的equals方法给覆盖了,这就是java中的多态。

操作下试试看
Student s1 = new Student("小明", 18);
Student s2 = new Student("小明", 20);
System.out.println(s1.equals(s2));//true

List中:

List<Student> list =new ArrayList<>();
list.add(new Student("小明",18));
list.add(new Student("小红",20));
list.add(new Student("小刚",22));

Student s =new Student("小明",18);
System.out.println(list.contains(s)); //true
Student s2 =new Student("小红",666);
System.out.println(list.contains(s2));//true

这时候会有人问了?我重写了equals方法和contains有什么关系?

问的好!

那是因为contains方法在执行时是依赖equals方法进行判断的

那么List还有那些方法在执行时是依赖equals方法的呢?

那可太多了

//间接依赖
int hashCode() 

//直接依赖
boolean contains(Object o) 
int  indexOf(Object o) 
int lastIndexOf(Object o) 
boolean  remove(Object o)
<E> remove(int index)
boolean containsAll(Collection<?> c)
boolean removeAll(Collection<?> c)

这些方法我们都可以按照我们重写equals的判断模式直接使用

重写equals时候为什么建议还要方法重写hashCode()?

因为重写了equals后还是用系统默认的hashCode算法时,不同的对象的hashCode可能是相同的,虽然概率极小。但是也要重写hashCode算法,也就是重写hashCode方法,来最大限度的减少概率,让其趋近于0;
代码界的一般约定:equals比较时相同的对象必须具有相同的哈希码。
如果hashCode相同的时候会对后续的比如HashMap有影响,默认是通过内存地址来进行算法计算的,通常会改为基于对象的字段值来计算哈希码

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

扩展:重写toString()方法 进行展示

@Override
    public String toString() {
        return "姓名:"+this.name+"\t年龄:"+this.age;
    }
    
//main中
Student s =new Student("小明",18);
System.out.println(s); //系统会默认调用toString() 
//System.out.println(s.toString());  //不信可以试试,和上边一样的

输出:姓名:小明 年龄:18
如果不重写就是输出了地址值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值