了解Java中的多重强制转换
如果你想马上读问题,请跳到最后一句 假设我们有一个接口和三个类:了解Java中的多重强制转换,java,inheritance,casting,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 po
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 =
// outer CastExpression
(B)(
// with its UnaryExpression being another CastExpression
(I)(b)
);
但问题出在这里。每次我看到一行带有多次转换的代码时,我都无法(逐字地)阅读它,因此,我无法理解它的含义
例如,假设我们有一行代码:
a = (B)(I)b;
a = (B)(I)b;
你怎么看这个<代码>a是对类型a对象的引用,它被赋予类型B对象的值(从左侧开始第一次转换)。但是等一下,b前面还有另一个演员。我们这里有什么?它是一个被转换为(B)对象的接口吗?或者它是一个b被转换为一个接口,而这个接口也被转换为a(b)
为了避免混淆,我尝试将其分解:
I temp = (I) b;// first line
a = (B) temp;// second line
因此,首先,由于b是一个I(因为它扩展了实现I的A),“第一行”被编译器和运行时接受
“第二行”虽然,我们有一个对对象a的引用,它被赋予类型B的值。乍一看,它没有什么问题。但后来我意识到I
不是A,也不是B,即使“第二行”中的强制转换可以使编译器相信它是B类型的对象,但在运行时它不应该被接受
因此,我想回答的主要问题是,我如何理解下面这句话:
将b
转换为I
,然后将其转换为b
。大概是因为您不能直接将b
转换为b
现在并没有很好的情况可以使用它,因为如果可能的话,即使是一次施法也应该避免。但是如果你想要
String s = (String) myHashMap;
要编译,您需要向上转换以防止编译器禁止明显非法的转换:
String s = (String) (Object) myHashMap;
当然,如果您的myHashMap
不为null,这将导致运行时ClassCastException
,但与前面的示例不同,它将编译。基于
a = (B)(I)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 =
// outer CastExpression
(B)(
// with its UnaryExpression being another CastExpression
(I)(b)
);
也就是说,它将b
强制转换为I
,然后将其强制转换为b
,然后将其分配给A
变量
然而,这两种类型看起来都不是必需的。如果
b
是b
的一个实例,那么它也是A
和I
现实或你不想要的答案的一个实例
这里真正的问题是一个粗心的傻瓜写了蹩脚的代码。
真正的解决办法是;要么不要写蹩脚的代码,要么修复代码
让我们继续做一个傻瓜或是你想要的答案
java中有两种类型的强制转换;上浇铸和下浇铸
上转换是将类型A的对象转换为接口I的实例;您正在“向上”转换继承树。
例如:
A aObject = new A();
I iObject = (I)aObject; // Up casting.
A aObject;
I iObject = new A();
aObject = (A)iObject;
向上转换的好处是编译器能够在编译时确定转换是否合法
向下投射是指将类型I的对象投射为类型A的对象;您正在“打倒”继承树。
例如:
A aObject = new A();
I iObject = (I)aObject; // Up casting.
A aObject;
I iObject = new A();
aObject = (A)iObject;
编译器在编译时不知道向下转换是否会成功。
因此,向下转换可能在运行时引发异常
你令人困惑的代码:a=(B)(I)B代码>是向上投射(安全)和向下投射(不安全)的示例
作为一个额外的奖励,演员阵容是不需要的。
将B对象直接指定给a引用总是安全的,因为B类扩展了a类
称呼:“粗心的傻瓜”似乎是一种很强的语言。
这不是一种强有力的语言,它是描述你的处境的最好的方式。
事实上,像这样编写代码的人应该被终止(或者,让你的竞争对手雇用他们)。也许你没有意识到,即使强制转换到I或A,b仍然是类型b的对象,它也不会失去它的本质。考虑铸造一种对java说“将我的对象视为I类型的对象”的方式。如果是B型的话,它也是A型的
因此,该指令告诉java‘使用我的对象,因为它是类型I,使用后立即作为类型B,通过声明,它也是类型A。因此没有编译或运行时错误
然后我们可以看到。它看起来也大多是无用和丑陋的。我会把它解释为两个不必要的强制转换。向接口强制转换似乎是错误的。I
不是B
,但是,I
可能是B
:)OP的实际困惑,我想,是他认为强制转换会改变对象的运行时类型。否。对象的运行时类型是固定的。但在编译时,编译器可以将其视为不同的类型(应该是特定运行时类型的超级类型)。值得一提的是,您应该(几乎)永远不需要强制转换。写得好的代码99%没有强制转换,但问题是{a=(B)(I)B;}在运行时也被接受。b是a I,所以这个类型没有问题,但是为什么可以将I转换为a b呢?如果我没有弄错的话,我不是B。双重强制转换的用例:@ZhongYu正确,不过最好通过修改实际的泛型类型和更宽的范围来解决。编译器总是允许缩小转换范围。这是它不好的原因之一。运行时出现的错误造成了巨大的伤害。这就是为什么这里有这么多的受访者反对收窄转换。Java官方术语“向上转换”是“扩大转换”,而“向下转换”是“收窄转换”。使用官方术语,可以直接在JLS中查找规则。“cast”的过去英语分词是“cast”。不用担心,@Massimo,你的英语几乎和我见过的任何人一样好