Java 为什么在 instanceOf 之后进行转换?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4186320/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:50:08  来源:igfitidea点击:

Why cast after an instanceOf?

javapolymorphisminstanceof

提问by JDelage

In the example below (from my coursepack), we want to give to the Squareinstance c1the reference of some other object p1, but only if those 2 are of compatible types.

在下面的示例中(来自我的课程包),我们希望为Square实例提供c1其他对象的引用p1,但前提是这两个对象是兼容类型。

if (p1 instanceof Square) {c1 = (Square) p1;}

What I don't understand here is that we first check that p1is indeed a Square, and then we still cast it. If it's a Square, why cast?

我在这里不明白的是,我们首先检查它p1确实是 a Square,然后我们仍然投射它。如果是Square,为什么要投射?

I suspect the answer lies in the distinction between apparent and actual types, but I'm confused nonetheless...

我怀疑答案在于明显类型和实际类型之间的区别,但我仍然感到困惑......

Edit:
How would the compiler deal with:

编辑:
编译器将如何处理:

if (p1 instanceof Square) {c1 = p1;}

Edit2:
Is the issue that instanceofchecks for the actualtype rather than the apparenttype? And then that the cast changes the apparenttype?

Edit2:
问题是instanceof检查实际类型而不是表观类型吗?然后演员改变了明显的类型?

Thanks,

谢谢,

JDelage

JDelage

采纳答案by Justin Niessner

Keep in mind, you could always assign an instance of Square to a type higher up the inheritance chain. You may then want to cast the less specific type to the more specific type, in which case you need to be sure that your cast is valid:

请记住,您始终可以将 Square 的实例分配给继承链上层的类型。然后,您可能希望将不太具体的类型转换为更具体的类型,在这种情况下,您需要确保您的转换有效:

Object p1 = new Square();
Square c1;

if(p1 instanceof Square)
    c1 = (Square) p1;

回答by Boris Pavlovi?

If c1is declared as a type of Squarethen casting is required. If it is a declared as an Objectthen casting is not needed.

如果c1声明为类型,Square则需要进行强制转换。如果它是声明为 anObject则不需要转换。

回答by Bozho

Because this particular syntactic sugaris not yet added to the language. I think it was proposed for Java 7, but it doesn't seem to have entered project coin

因为这个特殊的语法糖还没有添加到语言中。我认为它是为Java 7提出的,但它似乎没有进入项目币

回答by jjnguy

The compiler does not infer that since you are in the block, you have done a successful check for the type of the object. An explicit cast is still required to tell the compiler that you wish to reference the object as a different type.

编译器不会推断,由于您在块中,因此您已成功检查对象的类型。仍然需要显式转换来告诉编译器您希望将对象引用为不同的类型。

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;
}

In C# you can do the check and the cast in 1 call:

在 C# 中,您可以在 1 个调用中进行检查和转换:

c1 = p1 as Square;

This will cast p1to a Square, and if the cast fails, c1 will be set to null.

这将p1转换为 Square,如果转换失败,c1 将设置为null

回答by Jules

E.g. If you hand over p1 as of type Object, the compiler wouldn't know that it is in fact an instance of Square, so that Methods etc. wouldn't be accessible. The if simply checks for a certain type to return true/false, but that doesn't change the type of the variable p1.

例如,如果您将 p1 作为 Object 类型移交,编译器将不知道它实际上是 Square 的一个实例,因此将无法访问方法等。if 只是检查某种类型以返回真/假,但这不会改变变量 p1 的类型。

回答by Andreas Dolk

The test is done to prevent from ClassCastExceptionsat runtime:

完成测试是为了防止ClassCastExceptions在运行时:

Square c1 = null;
if (p1 instanceof Square) {
   c1 = (Square) p1;
} else {
   // we have a p1 that is not a subclass of Square
}

If you're absolutly positive that p1is a Square, then you don't have to test. But leave this to private methods...

如果您绝对肯定p1Square,那么您不必进行测试。但是把它留给私有方法......

回答by Carl Manaster

The variable p1 has whatever type it started with - let's say Shape. p1 is a Shape, and only a Shape, no matter that its current contents happen to be a Square. You can call - let's say - side() on a Square, but not on a Shape. So long as you are identifying the entity in question via the variable p1, whose type is Shape, you can't call side() on it, because of the type of the variable. The way Java's type system works, if you can call p1.side() when you happen to know it's a Square, you can alwayscall p1.side(). But p1 can hold not just Square Shapes, but also (say) Circle Shapes, and it would be an error to call p1.side() when p1 held a Circle. So you need another variable to represent the Shape which you happen to know is a Square, a variable whose type is Square. That's why the cast is necessary.

变量 p1 具有它开头的任何类型 - 让我们说 Shape。p1 是一个Shape,并且只是一个Shape,不管它当前的内容是否恰好是一个Square。您可以在 Square 上调用(比方说) side(),但不能在 Shape 上调用。只要您通过变量 p1(其类型为 Shape)识别有问题的实体,就不能对其调用 side(),因为变量的类型。Java 的类型系统的工作方式是,如果您在碰巧知道它是 Square 时可以调用 p1.side() ,则始终可以调用 p1.side()。但是 p1 不仅可以容纳方形,还可以容纳(比如说)圆形,当 p1 持有圆形时调用 p1.side() 将是错误的。所以你需要另一个变量来表示你碰巧知道是 Square 的 Shape,一个类型为 Square 的变量。那'

回答by Mark Peters

There's a difference between measuring if some object will fit in a box, and actually puttingit in the box. instanceofis the former, and casting is the latter.

测量某个物体是否适合放在盒子中与实际其放入盒子中是有区别的。 instanceof是前者,铸造是后者。

回答by Jay

Not to be obnoxious, but you have to tell the compiler what you want to do because the alternative would be for it to guess what you're trying to do. Sure, you might think, "If I'm checking the type of an object, OBVIOUSLY that must mean that I want to cast it to that type." But who says? Maybe that's what you're up to and maybe it isn't.

不要令人讨厌,但您必须告诉编译器您想做什么,因为另一种选择是让编译器猜测您要做什么。当然,您可能会想,“如果我正在检查对象的类型,显然这意味着我想将其强制转换为该类型。” 但是谁说呢?也许这就是你要做的,也许不是。

Sure, in a simple case like

当然,在一个简单的情况下,比如

if (x instanceof Integer)
{
  Integer ix=(Integer) x;
  ...

My intent is pretty obvious. Or is it? Maybe what I really want is:

我的意图非常明显。或者是吗?也许我真正想要的是:

if (x instanceof Integer || x instanceof Double)
{
  Number n=(Number) x;
... work with n ...

Or what if I wrote:

或者如果我写:

if (x instanceof Integer || x instanceof String)

What would you expect the compiler to do next? What type should it assume for x?

您希望编译器接下来做什么?它应该为 x 假设什么类型?

RE the comments that instanceof is obsolete or otherwise a bad idea: It can certainly be mis-used. I recently worked on a program where the original author created six classes that all turned out to be pages and pages long, but identical to each other, and the only apparent reason for having them was so he could say "x instanceof classA" versus "x instanceof classB", etc. That is, he used the class as a type flag. It would have been better to just have one class and add an enum for the various types. But there are also plenty of very good uses. Perhaps the most obvious is something like:

请注意 instanceof 已过时或其他坏主意的评论:它肯定会被误用。我最近在编写一个程序,其中原作者创建了六个类,这些类都长达一页又一页,但彼此相同,拥有它们的唯一明显原因是他可以说“x instanceof classA”与“ x instanceof classB”等,也就是他用class作为类型标志。最好只有一个类并为各种类型添加一个枚举。但也有很多非常好的用途。也许最明显的是:

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 ...
}

How would you do that without using instanceof? You could make the parameter be of type MyClass instead of Object. But then there's be no way to even call it with a generic Object, which could be highly desirable in many cases. Indeed, maybe I want a collection to include, say, both Strings and Integers, and I want comparisons of unlike types to simply return false.

如果不使用 instanceof,您将如何做到这一点?您可以使参数的类型为 MyClass 而不是 Object。但是,甚至无法使用通用对象来调用它,这在许多情况下可能是非常可取的。事实上,也许我想要一个集合,比如,同时包含字符串和整数,并且我想要不同类型的比较简单地返回 false。

回答by Grim

Old code wont work correctly

旧代码无法正常工作

The impield cast featureis justified after all but we have trouble to implement this FR to java because of backward-compatibility.

impield投功能毕竟是有道理的,但我们很难实现这个FR,因为向后兼容Java的。

See this:

看到这个:

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);
        }
    }
}

The current JDK would compile the usage of the second declared method. If we implement this FR in java, it would compile to use the first method!

当前 JDK 将编译第二个声明方法的用法。如果我们在java中实现这个FR,它会编译为使用第一种方法!