【问题标题】:Why verify obj class does not match instance class before typecasting in Java?为什么在 Java 中进行类型转换之前验证 obj 类与实例类不匹配?
【发布时间】:2016-01-05 14:25:58
【问题描述】:

我想使用自定义的 equals 方法比较两个人的统计信息,该方法将覆盖 Object 类中的 equals 方法。由于这个equals方法的返回类型将是一个布尔值,我知道我需要传入(Object obj)参数。当我定义新的 equals 方法时,我被告知我需要首先检查 obj 类是否与实例类不匹配。验证后,我将 obj 类类型转换为实例类,然后可以继续执行其余代码。

但是,我不明白为什么我需要验证 obj 类与实例类不匹配。我认为这两个类应该不匹配,因此需要类型转换。

谁能告诉我为什么我们需要验证 obj 类与实例类不匹配?我正在处理的代码写在下面。

public boolean equals(Object obj) {
    if (obj == null || obj.getClass() != this.getClass())
        return false;
    else {
        Person pp2 = (Person) obj;

        if (this.name.equals(pp2.name) && this.age == pp2.age)
            return true;
        else
            return false;
    }
}

public static void main(String[] args) {
     Person ps1 = new Person("Buddy", 14);
     Person ps2 = new Person("Buddy", 14);

     if (ps1.equals(ps2))
        System.out.println("Same");
}

【问题讨论】:

  • 可能有两个不同的类具有相同的变量。 Student vs Person,都有名字和年龄,但是他们是不同的类。
  • 在一个侧节点上,使用obj instanceof Person 将同时进行,检查类是否相等以及obj是否不为空
  • 既然 ps2 来自 Person 类,而 obj 来自 Object 类,那么在你可以类型转换之前调用 ps1.equals.ps2 类匹配验证不会总是失败任何事物?这就是我感到困惑的原因。
  • @OmarN ps2.equals(new Person()) 将创建人的 obj 实例。所以 getClass 将返回 Person 类。
  • 明白了。谢谢!

标签: java typecasting-operator


【解决方案1】:

你建议做的是:

public boolean equals(Object obj) {
    Person pp2 = (Person) obj;
    return (this.name.equals(pp2.name) && this.age == pp2.age);
}

这将违反equals() 方法协定,该协定明确规定,当两个对象不相等时,该方法必须返回 false。此处情况并非如此:该方法将改为抛出 ClassCastException(如果 obj 为 null,则抛出 NullPointerException)。

【讨论】:

  • 但是由于我们在调用 (ps1.equals(ps2)) 时是通过 equals 传递 ps2,并且 ps2 属于 Person 类,这是否意味着类类型将不匹配,因为obj 属于 Object 类吗?由于它们不匹配类,这就是为什么我不明白我们为什么要检查它。
  • 一个人是一个对象。将 Person 称为对象并不会更改其类型:它仍然是 Person,obj.getClass() 返回的实际类仍然是 Person。这就是多态性。它在现实生活中也很有效。虽然你的手机是 iPhone 6S,但我可以称它为“手机”、“电子产品”或“物体”,这并不能改变它仍然是 iPhone 6S 的事实。
  • 好的,我想我明白了。所以验证成功是因为 Object 类等于 Person 类,因为 Person 是 Object 的子类?
  • 差不多。您可以将 Person 实例称为 Object,因为 Person 类扩展了 Object 类。这就是为什么您可以使用 Person 作为参数调用 equals() 的原因。 obj.getClass() 返回 Person 类,因为 obj 实际上是 Person 类的一个实例。如果 obj 是对 Dog 实例的引用,它将返回类 Dog。但是 Dog 也可以称为 Object,因为它也扩展了 Object。
  • @sedpol 您是否考虑过阅读答案。它这么说。明确的。
【解决方案2】:

如果你不检查另一个obj的类型,那么当有人来电时你可能会得到一个ClassCastException

new Person("Jim",12).equals(new ArrayList())

你不想这样。你想返回 false 而不是崩溃。

【讨论】:

    【解决方案3】:

    你可以使用:

    if (obj instanceof Person){
    }
    

    【讨论】:

    • 使用 instanceof 而不是检查类身份会违反 equals 的约定,因为它破坏了对称性。
    • @Drunix:可能,是的。但是您可以匹配所有其他子类的 equals 实现以保持对称性。事实上,这实际上是由List 之类的东西完成的。即使容器类不同,它们也应该是相等的。
    猜你喜欢
    • 2012-11-14
    • 2022-01-13
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2012-07-14
    相关资源
    最近更新 更多