繁体   English   中英

理解 equals-Implementation:类型检查和 THEN 类型转换

[英]Understanding equals-Implementation: type-check and THEN type-cast

为什么要检查 object 的类型,然后通过类型转换创建新的 object?

有人可以提供一个例子,为什么以所示方式完成?

请在片段中查看我的评论。

 @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
 
        // After this check I know for sure that the object is an instance of Complex.
        if (!(o instanceof Complex)) {
            return false;
        }
        
        // Why is this cast necessary? I know (already) that is of type Complex. So I has all members Complex has.
        Complex c = (Complex) o;
       
        return Double.compare(re, c.re) == 0
                && Double.compare(im, c.im) == 0;
    }

从 Java 14 开始,您可以制作 instanceof 并一起投射。 更多信息请看这里:

https://openjdk.org/jeps/305

从规范来看,这是设计:

if (obj instanceof String s) {
     // can use s here
} else {
     // can't use s here
}

因为 Java 编译器在优化代码方面根本没有 go 那么远。 我认为可以实现这样的优化(虽然听起来说起来容易做起来难,但在 if 检查之后可能需要大量的工作才能使o算作Complex ),但是javac始终围绕着很少的优化而构建尽可能

人们确实发现需要明确的演员表是不合理的。 并想出了以下“改进”。 但这仍然只是语法糖。 从 Object 到 Complex 需要演员表。 在编译时这很清楚,不会像在其他一些语言中那样将 Object 变量提升为 Complex 变量。

在这种情况下,有一个奇怪的用法:

    if (!(o instanceof Complex c)) {
        return false;
    }       
    // c known here, weird as it is.
    ...

人们只会期待@Level_Up 的解决方案。

为什么要检查 object 的类型,然后通过类型转换创建新的 object?

没有创建新的 object。

在 Java 中,对象只能通过引用访问; 它们不能直接访问。 引用有类型,而对象有类。 The type of a non- null reference will always be a supertype of the class of the object to which it refers, but often the reference's type is not the exact class of the object.

 // Why is this cast necessary? I know (already) that is of type Complex. So I has all members Complex has.

Java 根据执行访问的引用类型对 object 访问执行编译时检查。 只有为引用类型定义的字段和方法可以通过该引用访问,即使它所引用的 object 可能是提供其他字段和方法的 class。 所以是的,您拥有 class Complex的所有方法和字段,但您需要强制转换才能访问它们。

因此,在您提出的相等测试习惯用法中,执行强制转换是为了获得对属于 class Complex对象的字段的访问权,但不一定是对其他类的对象的访问权。 这不会创建新的 object,而是创建对相同 object 的新引用。 变量c的声明也不会创建任何对象。 它为您提供本地存储以供参考,并为存储在那里的参考提供名称。 之后, co指的是相同的 object。

有人可以提供一个例子,为什么以所示方式完成?

正如已经讨论过的,强制转换是必要的,但instanceof测试不是,因为 Java 无论如何都会在运行时检查强制转换。 但是不兼容的强制转换会引发ClassCastException ,并且equals(Object)的约定指定该方法在这种情况下应该返回false ,而不是抛出异常。 因此,这将是一个替代方案:

 @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
 
        try {
            // The casts are necessary for accessing members re and im
            // defined by class Complex:
            return Double.compare(re, ((Complex)o).re) == 0
                    && Double.compare(im, ((Complex)o).im) == 0;
        } catch (ClassCastException e) {
            return false;
        }
    }

是不是比原版好? 不是我的眼睛。 异常处理增加了额外的认知负担,现在你必须内联两次。 并且 Java 强制转换具有运行时成本,所以如果幸运的话,编译器会将这对强制转换优化为相当于原始代码的......

 Complex c = (Complex) o;

... 反正。

或者,也许,然后,我们可以手动确保强制转换只进行一次,而不是将其留给编译器或 JIT:

 @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        Complex c;
 
        try {
            c = (Complex) o;
        } catch (ClassCastException e) {
            return false;
        }

        return Double.compare(re, c.re) == 0
                && Double.compare(im, c.im) == 0;
    }

不是比原版好? 再说一次,不是我的眼睛。 我们仍然有异常处理的认知负担(和运行时成本),而原始代码用来避免这种情况的instanceof检查在上下文中是简单而自然的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM