了解Java中的多个强制转换

时间:2017-02-09 17:48:17

标签: java inheritance casting

如果您想立即阅读该问题,请跳至最后一句。

假设我们有一个接口和三个类:

interface I{}

class A implements I{}

class B extends A {}

以下声明:

A a = new A();
B b = new B();

现在,有一种经典的转换方式,它允许我将类型A(父类)的引用转换为类型B的对象(子类),如下所示:

 a = b; //here a is no longer pointing at object A, and is now pointing at the same object b is pointing at.
 b = (B) a; // the casting is now accepted by the compiler and during runtime as well.

这里存在问题所在。每当我看到一行代码都有多个转换时,我就无法读取它(字面意思),因此我无法理解它的含义。

例如,假设我们有这行代码:

a = (B)(I)b;

你怎么读这个? a是对类型A的对象的引用,并且它被赋予类型B的对象的值(从左侧首先强制转换)。但是等一下,b之前还有另一个演员(I)。那么我们在这里有什么?它是一个被转换为(B)对象的接口吗?或者它是否被投射为界面,也被投射为(B)?

我试图将其分解以避免混淆:

I temp = (I) b;// first line
a = (B) temp;// second line

所以,首先,因为b是I(因为它扩展了实现I的A),所以编译器在运行时接受“第一行”。

“第二行”但是,我们引用了一个对象A被赋予了类型B的值。乍一看,它没有任何问题。但后来我意识到I不是A也不是B,即使“第二行”中的强制转换可以使编译器认为它是B类的对象,但它不应该在运行时被接受

所以我想回答的主要问题是如何解释以下行:

a = (B)(I)b;

4 个答案:

答案 0 :(得分:6)

现实或您不想要的答案

这里真正的问题是粗心的goofball编写了糟糕的代码。 真正的解决方案是;要么不写蹩脚的代码,要么修复代码。

让我们继续作为一个傻瓜或你似乎想要的答案

java中有两种类型的转换;向上和向下铸造。

向上转换是指将类型A的对象转换为接口I的实例;你在铸造" up"继承树。 例如:

A aObject = new A();
I iObject = (I)aObject;  // Up casting.

向上转换的好处是编译器能够在编译时确定转换是否合法。

向下转换是指将类型I的对象转换为类型A的对象;你在铸造" down"继承树。 例如:

A aObject;
I iObject = new A();

aObject = (A)iObject;

编译器在编译时不知道向下转换是否成功。 因此,向下转换可能会在运行时抛出异常。

令人困惑的代码:a = (B)(I)b;是向上投射(安全)和向下投射(不安全)的示例。

作为奖励,铸造绝不是必需的。 将B对象直接分配给A引用总是安全的,因为B类扩展了A类。

解决:"粗心的goofball" 似乎是强大的语言。 它不是强大的语言,它是描述你的情况的最好方法。 事实上,编写这样的代码的人应该被终止(可选地,让你的竞争对手雇佣他们)。

答案 1 :(得分:2)

基于Java language grammar,声明

a = (B)(I)b;

可能会更好地形象化:

a =
  // outer CastExpression
  (B)(
    // with its UnaryExpression being another CastExpression
    (I)(b)
  );

也就是说,它会将b转换为I,然后将其转换为B,然后将其分配给A变量。

然而,看起来这些演员表中的任何一个都不是必需的。如果bB的实例,则它也是AI的实例。

答案 2 :(得分:0)

 a = (B)(I)b;

b投射到I,然后将其投放到B。大概是因为你无法直接将b投射到B

现在还没有好的情况可以使用它,因为如果可能的话,应该避免一次性投射。但是,如果你想要像

这样的东西
String s = (String) myHashMap;

要编译,你需要upcast以防止编译器禁止明显非法的演员:

String s = (String) (Object) myHashMap;

当然,如果您的myHashMap不为空,这将导致运行时ClassCastException,但与之前的示例不同,它将进行编译。

答案 3 :(得分:0)

也许你没有明白,即使施放到I或A,b仍然是B型的对象,它的性质也不会松散。想办法说一下对java的看法'将我的对象视为I'的对象。然后,如果是B型,它也是A型。

因此,指令告诉java使用我的对象,因为它是I类型,并在使用它作为类型B之后立即使用它,通过声明,它也是类型A.因此没有编译或运行时错误。

然后我们可以看到它看起来也大部分都是无用的和丑陋的......