[英]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 并一起投射。 更多信息请看这里:
从规范来看,这是设计:
if (obj instanceof String s) {
// can use s here
} else {
// can't use s here
}
人们确实发现需要明确的演员表是不合理的。 并想出了以下“改进”。 但这仍然只是语法糖。 从 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
的声明也不会创建任何对象。 它为您提供本地存储以供参考,并为存储在那里的参考提供名称。 之后, c
和o
指的是相同的 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.