在类中equals()方法中使用instanceof出现的问题

前面我们对于equals()和==的区别进行了一个探究。在这个复习类的使用的时候我发现了一个关于instanceof的容易犯错的点,好让我们现在来看一段代码。

我们先定义一个Employee类:这里主要看类中

查看代码


public class Employee extends Person{
    private String name;
    private double salary;
    private LocalDate hireDay;

    public Employee(String name, double salary, int year,int month,int day) {
        this.name = name;
        this.salary = salary;
        hireDay = LocalDate.of(year,month,day);
    }

    public void raiseSalary(Double byPercent){
        double raise = salary *byPercent / 100;
        salary += raise;
    }
    @Override
    public String getDescription() {
        return "a employee wit a salary of " + this.salary;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Employee)) return false;
        Employee other = (Employee) o;
        return salary == other.salary;
    }

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

这里我们在定义一个Employee的子类Manager:

查看代码

public class Manager extends Employee{
    private double bonus;

    public Manager(String name, double salary, int year, int month, int day) {
        super(name, salary, year, month, day);
        bonus = 0;
    }

    public double getSalary()
    {
        double baseSalary = super.getSalary();
        return baseSalary + bonus;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Manager)) return false;
        if (o == null || getClass() != o.getClass()) return false;
        Manager manager = (Manager) o;
        return bonus == manager.bonus;
    }

}

在测试类我们分别生成Manager类和Employee类:

        Manager m = new Manager("Jack", 50000, 1999, 12, 25);
        Employee e = new Employee("Jack", 50000, 1999, 12, 25);
        System.out.println(e.equals(m));//true
        System.out.println(m.equals(e));//false

这时我们发现这不符合equals()方法的一致性,因此使用instanceof来判断是否是相同的类型是存在一定的问题的。好现在让我们来了解一下instanceof关键字的原理,根据jvm对于instanceof关键字的规范,我们将instanceof的伪代码写出来:

查看代码

    //obj instantceof T
    if (obj == null){
        return false;
    }else{
        try {
            T temp = (T) obj;
            return true;
        }catch (ClassCastException e){
            return false;
        }
    }

上面的代码的意思就是当obj为null时返回false,当obj可以转换成T类型不会出现异常时返回true。

对于S instanceof T,我对于S不同的三中类型都进行了判断和验证:

查看代码

        //第一种情况S为普通类
        Employee s = new Employee();
        Manager s1 = new Manager("jack", 343.5, 1998, 3, 2);
        Cat s3 = new Cat();
        System.out.println(s instanceof Employee );//s是Employee类 true
        System.out.println(s1 instanceof Employee);//s1是Employee的子类 true
        //System.out.println(s3 instanceof Employee);//不兼容的类型: demo0.Cat无法转换为demo0.Employee
        System.out.println(s instanceof Cloneable);//s实现了Cloneable true
        //第二种情况S为接口类
        IntConsumer s4 = new IntConsumer() {
            @Override
            public void accept(int value) {
            }
        };
        System.out.println(s4 instanceof Object);//true
        //第三种情况S为数组
        int[] list = new int[19];
        System.out.println(list instanceof Object);//true

好我们现在回来看之前的那个出现问题的代码:

        Manager m = new Manager("Jack", 50000, 1999, 12, 25);
        Employee e = new Employee("Jack", 50000, 1999, 12, 25);
        System.out.println(e.equals(m));//true
        System.out.println(m.equals(e));//false

对于m.equals(e)的返回值为false,通过我们上面的分析我们可以知道,在equals中我们是用instanceof进行判断的,在判断中我们会将Employee转成Manager这时就发生了异常,在java中会自动的帮我们向上转型但是我们不会轻易的向下转型。所以下次我们覆写类中的equals()方法时我们尽量不用instanceof关键字对对象进行判断。

posted on 2022-03-27 14:45  vernier_caliper  阅读(52)  评论(0)    收藏  举报