java8重写equals的不解?

在学Java中,遇到一个重写object类的equals方法,代码如下

public class Phone {
    public String name;
    public int price;

    public Phone(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    //equaLs方法进行重写:
    public boolean equals(Object obj) {
        System.out.println(obj); //Phone@1b6d3586
        if (obj instanceof Phone) {//是否属于Phone类的对象
            Phone other = (Phone) obj;//将obj转为Phone类型:
            if (this.getName().equals(other.getName()) && this.getPrice() == other.getPrice()) {
                return true;
            }
        }
        return false;
    }
}

我定义了一个Phone类,有name和price两个属性,重写equals方法,只要name和price都一样就认为一样。

然后我测试了一下:

public class Test {
    public static void main(String[] args) {
        Phone p1 = new Phone("P30",5000);
        Phone p2 = new Phone("P30",5000);
        System.out.println(p1.equals(p2)); //true
    }
}

上面结果是true,达到效果,我不理解的是为什么需要Phone other = (Phone) obj;进行强转,在equals方法第一行我打印了obj结果是Phone@1b6d3586,那么是不是可以说明obj其实就是Phone的实列?如果是为什么需要强转?如果不是那么obj instanceof Phone结果是false也运行不进去啊?

阅读 2.3k
4 个回答
在equals方法第一行我打印了obj结果是Phone@1b6d3586,那么是不是可以说明obj其实就是Phone的实列?如果是为什么需要强转?如果不是那么obj instanceof Phone结果是false也运行不进去啊?

是的没错,你传入的这个对象是Phone类型的一个实例,所以你不用怀疑为什么能进去if分支
接下来注意 你重写的是所有类的父类Object的equals方法,这个方法的形参是一个Object类型的对象,在JAVA里任何类型都是Object类型的子类,说白了这里只是告诉编译器什么类型都可以往里传,如果这里不是Object类型的形参,那你覆盖的就不是Object类的equals方法了而只是自己写了一个全新的equals方法,这当然也可以,而且比较的结果仍然是正确的,然而不重写Object类的equals方法的话,Java的标准库和其他第三方库通常依赖于equals方法的重写(Object类里的)来正确地比较对象,是会带来问题的。
好了现在问题变成为什么又要强转回去了,因为编译器现在只知道你传入的对象是一个Object类型的对象,我就偏偏不强转了怎么滴,可是Object类有getName()方法吗?有getPrice()方法吗?所以编译器就不乐意了,你只告诉我你是Object类型的你又没有这些方法,肯定就给你报错了。(不信你可以写一下试试,就不强转看看代码报不报红)
所以我们强转,告诉编译器其实刚才我只是装的,我只是为了满足你让我重写这个方法的门槛而已,现在我能重写这个方法了我就不演了,其实我是Phone哥,我有getName()方法和getPrice()方法,接下来就是就掏出自己的方法一顿操作了。
注意楼上有提及到你重写了equals方法就一定要重写hashCode方法,如果你不重写hashCode方法的话在把自定义对象丢进集合类的时候有意外的惊喜哦,至于为什么就不是这篇问题的范畴了,自行百度理解即可。

企业微信截图_16848317968279.png

public boolean equals(Object obj) {
    if (obj instanceof Phone) {
        Phone other = (Phone) obj;
        if (this.getName().equals(other.getName()) && this.getPrice() == other.getPrice()) {
            return true;
        }
    }
    return false;
}

将你的代码转成 Kotlin, 你会发现

class Phone(val name: String, val price: Int) {

    override fun equals(other: Any?): Boolean {
        if (other is Phone) {
            // 这块不需要再 (Phone)
            return other.name == this.name && other.price == this.price
        }
        return false
    }
}

但是将代码kt反编译后呢

public boolean equals(@Nullable Object other) {
  if (!(other instanceof Phone)) {
     return false;
  } else {
     return Intrinsics.areEqual(((Phone)other).name, this.name) && ((Phone)other).price == this.price;
  }
}

在JDK14之后,可以这样使用

@Data
public class Mobile {
    private String name;
    private Integer price;

    @Override
    public boolean equals(Object other) {
        // JDK14之后可以这样使用
        if (other instanceof Mobile mob) {
            return Objects.equals(mob.getName(), this.getName()) && Objects.equals(mob.getPrice(), this.getPrice());
        }
        return false;
    }
}

回到这个问题本身。 https://stackoverflow.com/questions/4186320/why-cast-after-an-instanceof

public class A {
    public static void draw(Square s){...} // with implied cast
    public static void draw(Object o){...} // without implied cast
    public static void main(String[] args) {
        final Object foo = new Square();
        if (foo instanceof Square) {
            // 这块会有兼容性问题
            draw(foo);
        }
    }
}

另外:重写equals后别忘记重写hashcode

推荐问题
宣传栏