当对象没有实际实现接口时,您可以将对象转换为接口吗?例如:将对象投射到未实现的接口
矩形类不实现可食用
Rectangle cerealBox = new Rectangle();
Edible e;
e = (Edible) cerealBox;
是这有效吗?
当对象没有实际实现接口时,您可以将对象转换为接口吗?例如:将对象投射到未实现的接口
矩形类不实现可食用
Rectangle cerealBox = new Rectangle();
Edible e;
e = (Edible) cerealBox;
是这有效吗?
不可以。因为接口没有实现,你会得到一个ClassCastException。
这将编译,但您将在运行时得到ClassCastException
,因为Rectangle
不会执行Edible
。
为什么这甚至编译?毕竟,编译器可以确定Rectangle
没有实现Edible
。因为参考变量cerealBox
可以在任何时候参考Rectangle
的一些未知子类,它们实现了Edible
。
public class EdibleRectangle extends Rectangle implements Edible {
//...
}
所以编译器必须允许投,但类型将在运行时进行检查,导致ClassCastException
如果不是Edible
。
请注意,如果你让Edible
一类,甚至abstract
,那么编译器会生成就投一个错误,因为它确定一个Rectangle
不能是Edible
,因为Rectangle
不继承Edible
。因为Java不允许扩展多个类,所以Rectangle
的任何子类都可以是Edible
。
还要注意的是,如果你做Rectangle
final
,那么编译器会生成就投一个错误,因为可以有没有Rectangle
如EdibleRectangle
上述子类可以实现Edible
接口。
在这种情况下编译器不会抱怨,如果你写这个,但是在运行时你会得到一个未经检查的运行时异常:特别是ClassCastException
。未经检查的运行时异常通常会由于完全可预防的错误代码而指示异常 - 在这种情况下,可能会阻止非法投射。
如何防止此异常?
如果您必须将一个变量类型转换为另一个变量类型,则为了防范此异常,应首先使用类型比较运算符instanceof
执行检查。例如:
if (cerealBox instanceof Edible) {
Edible e = (Edible) cerealBox;
// munch away
}
else {
// spit it out - it's not edible (or there's nothing there)
}
该检查将只返回true
如果变量是针对被测试的类型(或类型的子类型),或者如果它被实现对所测试的接口。如果变量是null
它将返回false
。
为什么编译器会让你做危险的事情?
如果被投射的类型未被标记为final
并且该投射属于界面,编译器将不会为可能非法演员提供错误。这是因为:
Rectangle
新亚型,这可能最终会被赋给变量cerealBox
:变量是多态性;和Rectangle
的任何这样的子类型可以实施Edible
。因此应该允许这种转换(参见下面的例子)。程序员应该使用instanceof
来防止ClassCastException
。
public class Soggy extends Rectangle implements Edible {}
...
// cerealBox is actually Soggy: it is polymorphic
Rectangle cerealBox = new Soggy();
if (cerealBox instanceof Edible)
Edible e = (Edible) cerealBox;
编译器会给出错误用于如果石膏:
源类型被标记final
,也不它或它的超类型实现该接口被铸造到;
public class Card {} // not edible
public final class Rectangle extends Card {} // final, not edible
...
Rectangle cerealBox = new Rectangle();
Edible e = (Edible) cerealBox; // won't compile
铸件是一类,并且源类型不是那类的子类型。
public class Circle {}
// neither this nor its subtypes will ever be Circle
public class Rectangle {}
...
Rectangle cerealBox = new Rectangle();
Circle e = (Circle) cerealBox; // won't compile
在这两种情况下,编译器可以告诉该转换将是非法的,无论你的代码的任何潜在的延伸。因此它阻止你这样做。
参考文献:
ClassCastException
docsinstanceof
:Java教程>平等关系,和条件运算>The Type Comparison Operator instanceof
你为什么不试试? – 2015-02-11 00:14:49
在这里问一个可能的错误答案或混淆答案的答案,而不是直接尝试并直接得到正确的答案是否更有效率? – EJP 2015-02-11 00:16:14