2015-02-11 57 views
-4

当对象没有实际实现接口时,您可以将对象转换为接口吗?例如:将对象投射到未实现的接口

矩形类不实现可食用

Rectangle cerealBox = new Rectangle(); 
Edible e; 
e = (Edible) cerealBox; 

是这有效吗?

+4

你为什么不试试? – 2015-02-11 00:14:49

+4

在这里问一个可能的错误答案或混淆答案的答案,而不是直接尝试并直接得到正确的答案是否更有效率? – EJP 2015-02-11 00:16:14

回答

0

不可以。因为接口没有实现,你会得到一个ClassCastException。

2

这将编译,但您将在运行时得到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

还要注意的是,如果你做Rectanglefinal,那么编译器会生成就投一个错误,因为可以有没有RectangleEdibleRectangle上述子类可以实现Edible接口。

0

在这种情况下编译器不会抱怨,如果你写这个,但是在运行时你会得到一个未经检查的运行时异常:特别是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; 

编译器会给出错误用于如果石膏:

  1. 源类型被标记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 
    
  2. 铸件是一类,并且源类型不是那类的子类型。

    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 
    

在这两种情况下,编译器可以告诉该转换将是非法的,无论你的代码的任何潜在的延伸。因此它阻止你这样做。

参考文献: