在下面的示例中(来自我的课程包),我们想为Square
实例c1
提供一些其他对象p1
的引用,但前提是这两个对象是兼容类型。
if (p1 instanceof Square) {c1 = (Square) p1;}
我在这里不明白的是,我们首先检查p1
确实是Square
,然后我们仍将其强制转换。如果是Square
,为什么要强制转换?
我怀疑答案在于表观类型和实际类型之间的区别,但是我还是很困惑...
编辑:编译器将如何处理:
if (p1 instanceof Square) {c1 = p1;}
Edit2:是instanceof
检查actual类型而不是apparent类型的问题吗?然后强制转换更改apparent类型?
谢谢,
JDelage
请记住,您始终可以将Square的实例分配给继承链更高一级的类型。然后,您可能需要将不太具体的类型转换为更具体的类型,在这种情况下,您需要确保您的转换有效:
Object p1 = new Square();
Square c1;
if(p1 instanceof Square)
c1 = (Square) p1;
编译器不会推断出由于您位于块中,因此您已经成功检查了对象的类型。仍然需要显式强制转换,以告知编译器您希望将对象引用为其他类型。
if (p1 instanceof Square) {
// if we are in here, we (programmer) know it's an instance of Square
// Here, we explicitly tell the compiler that p1 is a Square
c1 = (Square) p1;
}
在C#中,您可以进行检查和强制转换1次调用:
c1 = p1 as Square;
这会将p1
强制转换为Square,如果强制转换失败,则c1将设置为null
。
impield cast feature毕竟是合理的,但是由于向后兼容,我们很难将此FR实现为Java。
查看此:
public class A {
public static void draw(Square s){...} // with impield cast
public static void draw(Object o){...} // without impield cast
public static void main(String[] args) {
final Object foo = new Square();
if (foo instanceof Square) {
draw(foo);
}
}
}
当前的JDK将编译第二个声明方法的用法。如果我们在Java中实现此FR,它将使用第一个方法进行编译!
[测量某个对象是否适合放入盒子与实际之间有区别。 instanceof
是前者,而投射是后者。
always调用p1.side()。但是p1不仅可以容纳正方形,而且可以(例如)容纳圆形,并且当p1容纳一个圆形时调用p1.side()是错误的。因此,您需要另一个变量来表示您碰巧知道的Shape,即Square,即类型为Square的变量。这就是为什么必须进行强制转换。
c1
声明为Square
类型,则需要强制转换。如果将其声明为Object
,则不需要强制转换。 ClassCastExceptions
:Square c1 = null;
if (p1 instanceof Square) {
c1 = (Square) p1;
} else {
// we have a p1 that is not a subclass of Square
}
如果您完全肯定p1
是Square
,则无需测试。但这留给私有方法...
当然,在简单的情况下
if (x instanceof Integer)
{
Integer ix=(Integer) x;
...
我的意图很明显。还是?也许我真正想要的是:
if (x instanceof Integer || x instanceof Double) { Number n=(Number) x; ... work with n ...
或者如果我写了怎么办:
if (x instanceof Integer || x instanceof String)
您希望编译器接下来做什么? x应该采用哪种类型?RE认为instanceof已过时,或者否则是个坏主意:肯定会被误用。我最近在一个程序上工作,其中原始作者创建了六个类,这些类最终都是一页一页又一页,但是彼此完全相同,并且拥有它们的唯一明显原因是他可以说“ x instanceof classA”与“ x instanceof classB”等。也就是说,他使用该类作为类型标志。最好只有一个类并为各种类型添加一个枚举。但也有很多很好的用途。也许最明显的是这样的:
public MyClass { int foo; String bar; public boolean equals(Object othat) { if (!(othat instanceof MyClass)) return false; MyClass that=(MyClass) othat; return this.foo==that.foo && this.bar.equals(that.bar); } ... etc ... }
[不使用instanceof怎么办?您可以使参数的类型为MyClass而不是Object。但是,甚至没有办法用通用对象来调用它,这在很多情况下是非常可取的。确实,也许我想让一个集合同时包含Strings和Integers,并且我希望比较不同类型只是返回false。
此(旧方式):
void outputValue(Object obj) {
if (obj instanceof String) { // Compare
String aString = (String) obj; // New variable & explicit casting
System.out.println(aString.toUpperCase()); // Access member
}
}
可以简化为此:
void outputValue(Object obj) { if (obj instanceof String aString) { // Compare and cast (if true) System.out.println(aString.toUpperCase()); // Access member } }
参考:https://jaxenter.com/pattern-matching-for-instanceof-in-java-14-169830.html