我在接受采访时被问到这个问题。它让我完全措手不及。
你有一个超类和一个子类。 class B
是A
的子类。这两个类都具有相同函数foo()
的实现。
是否可以编写一段代码使编译器不知道对象的类型是什么?在这种情况下,对象是b
以下
A b = new B();
然后你会做一个函数调用,在执行之前不会知道类型。
这是我在白板上的答案:(A)b.foo();
答案 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();
}
但是,我不认为这是他们正在寻找的答案,因为提到A
和B
(并且它应该适用于Java和C#)。
他们可能一直在寻找(基本上你自己说的话)可能是这样的:
public void MyMethod(A a)
{
a.foo(); // What foo() method is called? The one from A or the one from B?
}
您可以使用A
和B
的实例作为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,编译器会输入代码来确定运行时的类型。