将已知类型的引用转换为类型层次结构之外的接口

时间:2013-05-02 20:36:05

标签: java oop casting

假设你有一个像这样的干净课程:

public class A {
    // Stuff
}

这样的界面:

public interface G {
    // Stuff
}

为什么我可以这样做:

A a = new A();
((G) a) // No errors thrown

我无法理解为什么当它们彼此无关时,应该可以从A类转换到接口G.有人可以向我解释一下吗?


后续。如果我做以下事情:

public class C implements G {
    // Stuff
}

这不会编译:

((C) a)

实现接口的类和接口之间有什么区别?

编辑:我收到编译错误说:

  

无法从A转换为C

6 个答案:

答案 0 :(得分:7)

强制转换意味着您比编译器更了解什么是有效的。您告诉编译器关闭并跟随您的线索。编译器可以在一些情况下告诉演员表是无效的,但很容易被愚弄。

大多数强制转换都倾向于从Object到其他东西,例如从非泛化集合中获取对象或使用PortableRemoteObject.narrow获取远程对象时。这些强制转换总是编译,因为你所投的任何内容(只要它是一个Object,而不是一个原语)总是一个有效的Object子类。

Reference Type casting (5.5.1)部分的Java语言规范中有一些强制转换规则。如果编译器可以弄清楚类之间没有关系(编译器可以告诉类是不同的,也不是另一个的子类)那么它将拒绝转换。

添加的示例很有趣,它失败了,因为编译器有足够的信息来判断转换是无效的。如果您将代码更改为:

    A a = new A();
    G g = (G)a;
    Object o = a;
    C c = (C)o;

然后它再次编译好(即使它同样错误)。

答案 1 :(得分:2)

这在编译时是允许的,因为Java编译器允许你这样做;它假设你知道你在做什么。

但是,JVM会计算出来并在运行时抛出ClassCastException

答案 2 :(得分:2)

这里的问题是因为G是一个接口,所以有可能存在A的子类来实现G。因此,至少可能在运行时,a中存储的对象类型实现G

“但我刚刚指定a包含类型A!愚蠢的编译器!”重要的是要记住,在评估强制转换的潜在成功时,编译器只查看变量的编译时类型。因此,编译器不会试图找出变量中实际存在的内容,而只是查看变量本身的类型。

请注意,如果您将A声明为final,那么这将成为编译时错误,因为现在编译器知道没有A的子类和{{1 }}本身不实现A,因此演员可以从不在运行时成功。

最后,相同的逻辑适用于将G转换为CA不是从C派生的,并且编译器知道没有{{1的子类派生自A(因为它们在某些时候都来自C!)所以演员阵容不可能在运行时成功。

答案 3 :(得分:1)

当然,但这也是有效的:

public class A {}
public class B {}

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

你几乎可以投射任何东西,当你知道你想要什么类型时,你可以投射。

(但是当你使用一些强制转换时,比如上面的例子,当Java意识到它不能正确投射时,你会在运行时获得ClassCastException。)

答案 4 :(得分:1)

编译器不一定知道a是否实现G

Casting几乎告诉编译器接受这个变量,并将其视为一个不同的类型。

如果您尝试对cast变量执行操作,就好像它实现了G(当它没有)时,您将收到运行时错误

答案 5 :(得分:1)

只能在运行时检查转换正确性。所以在你的例子中,即使你可能很明显,对于程序来说,在实际运行之前它不会知道它是不正确的,并且尝试将变量a转换为接口G.此时它将抛出ClassCastException。 / p>