从编译器隐藏对象的类型

时间:2014-05-17 18:41:06

标签: c# java

我在接受采访时被问到这个问题。它让我完全措手不及。

你有一个超类和一个子类。 class BA的子类。这两个类都具有相同函数foo()的实现。

是否可以编写一段代码使编译器不知道对象的类型是什么?在这种情况下,对象是b以下

A b = new B();

然后你会做一个函数调用,在执行之前不会知道类型。

这是我在白板上的答案:(A)b.foo();

3 个答案:

答案 0 :(得分:1)

在C#中,您可以使用dynamic关键字来实现动态输入。

public void MyMethod(dynamic myVar) 
{
    // The compiler don't know the exact type of myVar
    // Does myVar have a foo() method? if not, we get a runtime error.
    myVar.foo();  
}

但是,我不认为这是他们正在寻找的答案,因为提到AB(并且它应该适用于Java和C#)。

他们可能一直在寻找(基本上你自己说的话)可能是这样的:

public void MyMethod(A a)
{
    a.foo();    // What foo() method is called? The one from A or the one from B?
}

您可以使用AB的实例作为MyMethod的参数,因为B具有 is-a 关系(它继承{)A。编译器将a视为A的实例,即使它可能是B的实例。

调用了哪个foo()方法?这取决于B是否会覆盖A foo()的实施或隐藏它。如果隐藏它,则调用A的方法,这是在编译时确定的,a实际上具有什么类型并不重要。

如果它覆盖foo()(很可能是这种情况),则在运行时确定。由于编译器不知道a的确切类型,因此在运行时根据a的{​​{3}}查找正确的调用方法。

所以编译器知道类型(它是一个 A),但它不知道确切的类型(它是一个子类还是不?)。


作为旁注。 (A)b.foo();会将foo()返回的值转换为A。如果您想在调用b之前将A投射到foo(),则应添加一组额外的括号:((A)b).foo();。但是,转换是不必要的,因为b已经声明为A变量(A b = ..)。

答案 1 :(得分:0)

您可以使用反射来创建编译器不知道的某种类型的对象(只能在运行时解析)。

如果你具体指的是语句new B(),那么不 - 你正在告诉编译器确切地说正在创建什么类型。

答案 2 :(得分:0)

至少在C#中你可以使用dynamic,编译器会输入代码来确定运行时的类型。