Java 个对象的比较

Comparison of Java objects

我是 Java 的新手,正在阅读一本 Java 的书;在某一时刻,它讨论了何时您可能想要重写内置函数 equals()。例如,如果一个对象具有可变 ID,而两个对象具有相同的 ID,您可能希望将它们视为相等。它给出了看起来或多或少像这样的示例代码:

public boolean equals(Object obj) {
    if((obj != null) && (obj instanceof myClass)) {
        myClass object1 = (myClass)obj;
        if(this.ID == object1.ID) {
            return true;
        }
    }
    return false;
}

我不完全明白第三行是怎么回事。我不确定为什么它是必要的,你不能只比较 if() 语句中的 obj.ID 和 this.ID。我的猜测是,这是因为 obj 只是被声明为可能没有 ID 的通用对象,所以您需要创建一个新对象 object1,它具有正确的 class 以查看 ID。

我说得对吗?那条线到底发生了什么?

在您的代码中 Object obj 是对对象的 引用。此时的代码不假设它是哪种类型的对象。

当你这样做时

myClass object1 = (myClass) obj;

您正在将 reference 的类型转换为一个对象,该对象要么成功,因为它是该类型的一个实例,要么因抛出 ClassCastException 而失败。

这会创建一个新的引用,但基础对象不会因此而改变,也不会被复制。

注意:obj != null 检查是多余的,因为 null 不是任何 class 的 instanceof,也不会触发异常。即

Object o = null;
boolean b = o instanceof Object; // always false, never throws an exception.

可以阅读此方法的较短版本。

public boolean equals(Object obj) {
    if(obj instanceof myClass) {
        myClass object1 = (myClass)obj;
        return ID == object1.ID;
    }
    return false;
}

甚至

public boolean equals(Object obj) {
    return obj instanceof myClass && ID == ((myClass) obj).ID;
}

在 Java 8 你可以写

public boolean equals(Object obj) {
    return Optional.ofNullable(obj)
                   .filter(o - > o instanceof myClass)
                   .map(o -> (myClass) o)
                   .filter(m -> ID == m.ID)
                   .isPresent();
}

是的。第三行在 if 语句中,上面写着 obj instanceof myClass。那时你知道它是 myClass 类型。假设 myClass 在您的代码中有一个 ID,那么您就知道这两个对象都有 ID 属性,您可以使用它们进行比较。

研究术语 "Object Casting"。

obj instanceof myClass 确保 objthis 的类型相同。现在我们知道将 and Object obj 转换为 myClass object1

是安全的

不需要 null 的测试,因为 instanceof 对于 nulls 是 false

只需使用:

if (obj instanceof myClass) {

否则,假设 ID 是原语(尤其不是 String),您的代码就没问题。

您的猜测几乎是正确的:obj 被声明为 Object 并且 Object 可以是任何类型,例如 String,它不必成员名为 ID,因此,您不能只看它来比较。因此,您引用的代码首先检查 obj 是否属于同一类型(如果不是,那么您知道它不相等),然后(在您询问的行上) casts 到那个类型。

我说过,你的猜测 几乎 是正确的,因为你建议创建一个 myClass 类型的新对象。这不是真的。赋值 myClass object1 = (myClass)obj; 不会创建任何新对象,它只是使新变量 object1 引用 obj 引用的相同对象 ,并且告诉编译器它现在应该知道该对象实际上是 myClass.

类型

在第 3 行,没有创建任何对象。

关于java,您首先需要了解的是,有基元,例如intchardoubleobjects,它们是其他一切,objects 总是通过引用访问。

因此,Object obj 是对类型 Object 对象的引用,并且在运行时它将引用某个对象。

然后,再往下说,当您说 myClass object1 时,您没有创建任何对象;您只是声明了一个名为 object1 的变量,它将引用 myClass 类型的对象。但是还没有对象。

因此,当您说 myClass object1 = (myClass)obj; 时,您是在将引用 obj 分配给引用 object1。由于在不同类型之间进行赋值通常是无效的,因此您使用 type cast(myClass) 部分)告诉编译器您知道自己是什么这样做,并且您确定 obj 将指向 myClass 类型的对象。因此,编译器允许您进行赋值。

赋值后,objobject1都指向了同一个对象,但是object1现在的用处是,可以把这个对象看成一个类型的对象myClass,因此您可以访问其成员。