当我编译以下代码时,我只在运行时看到错误 “无法将”Foo1“类型的对象强制转换为”Foo2“
为什么编译器在编译期间没有显示此错误?
public void Start()
{
Foo1 objFoo1 = new Foo1();
Foo2 objFoo2 = (Foo2)objFoo1;
//objFoo1.FooA = 10;
//Console.WriteLine(objFoo2.FooA);
}
public class Foo1 {}
public class Foo2 : Foo1 {}
答案 0 :(得分:2)
编译器不够聪明,不知道objFoo1
实际上是一个简单的Foo1
。它不会深入分析您的源代码以确定它。它只看到objFoo1
是Foo1
,Foo2
来自Foo1
,因此演员表是合法的。如果改为将其更改为(int) objFoo1
,它会在编译时弹出,因为编译器可能会发现没有可能的方法将Foo1
转换为整数。
想象一下,两个声明之间有1000行代码,其中许多代码对objFoo1
进行了各种分配。编译器必须做很多努力才能尝试确定objFoo1
中究竟是什么对象。一般来说,它并不总是能够这样做。编译器只需在面值处获取静态类型信息并假设objFoo1
是某种类型的Foo1
对象而不是更多。这样它就不会拒绝你的简单测试程序,而是接受一个更复杂的程序。
在这种情况下,拒绝代码也不是编译器的工作。尽管不可否认,你有可能通过非法演员有意尝试生成ClassCastException
。这样做是不寻常的,但并非违法。
在这些方面,还有其他情况下编译器的静态代码分析可能被欺骗。这将无法编译:
return;
System.out.println("hello world!"); // compile error - unreachable code
虽然它在语义上是相同的,但编译得很好:
if (true) return;
System.out.println("hello world!");
答案 1 :(得分:1)
没有编译时错误,因为可能你的代码可以工作,因为objFoo1
实际上可能是Foo2
类型 - 编译器根本不知道在执行时,对象的实际类型可能不同。
请记住,多态性允许您引用派生类型作为其基类型的实例 - 编译器只知道并关心引用的声明类型 - 在这种情况下,引用表明潜在有效这是允许的。
答案 2 :(得分:0)
Foo2是Foo1。 Foo1不是Foo2,但这是演员试图断言的内容。现实生活的比喻是:通常,孩子从父母那里继承钱,但父母不会从子女那里继承钱。
我觉得你的痛苦在这里。当我第一次开始OOP时,我遇到了很多这类问题,我花了一些时间来绕过一些细微差别。如果我有一个Foo1并且我希望它获得添加的功能,为什么我不能只是向另一个方向投射并获得那些额外的属性和方法?不幸的是,这不是它的工作原理。然而,随着时间和练习,它会变得更容易。
答案 3 :(得分:-1)
因为编译器遵守你的指令。然后它将允许编译代码。
Foo2 objFoo2 = (Foo2)objFoo1;
如果你不强迫它,它会给你一个编译错误。
Foo2 objFoo2 = objFoo1; // kaboom
无论如何,真正的原因是你实例化对象Foo1,它是Foo2的基础,但不是Foo2。
如果你这样做,它会起作用
Foo1 foo1 = new Foo2();
Foo2 foo2 = foo1 as Foo2;