🧩 一、什么是方法隐藏(Method Hiding)
在 C# 中,如果子类定义了一个与父类同名的方法,并且使用 new 关键字, 那么子类的方法就会隐藏父类的方法。
这叫做 方法隐藏(Method Hiding),也称为 “静态多态” 或 “伪多态”。
💡 二、为什么叫“隐藏”?
因为父类的方法仍然存在,只不过:
当你用子类类型变量访问时,会调用子类的方法;
当你用父类类型变量访问时,会调用父类的方法。
🟡 它看起来像多态,但其实是编译时决定的(静态绑定), 并不是真正的“运行时多态”。
💻 三、示例代码对比说明
using System;
class Animal
{
    public void Speak()
    {
        Console.WriteLine("动物在叫。");
    }
}
class Dog : Animal
{
    // new:隐藏父类方法
    public new void Speak()
    {
        Console.WriteLine("狗在汪汪叫。");
    }
}
class Program
{
    static void Main()
    {
        Dog d = new Dog();
        d.Speak();         // ✅ 输出:狗在汪汪叫。
        Animal a = new Dog();
        a.Speak();         // ⚠️ 输出:动物在叫。
    }
}🔍 四、运行机制分析
d.Speak():变量是Dog类型 → 调用子类的Speak();a.Speak():变量是Animal类型 → 调用父类的Speak()。
🔸 因为
Speak()不是virtual的,所以编译器在编译阶段就决定调用哪个版本, 程序运行时不会再去“动态绑定”。
⚙️ 五、与真正多态(virtual/override)的对比
🧠 六、打个比喻帮助理解
✅ 七、总结一句话
方法隐藏实现的“多态”是表面上的多态(静态多态), 它只是让子类重新定义了一个同名方法, 并不会根据对象实际类型在运行时动态决定调用哪个方法。
换句话说:
new是“重新写一个”,override是“接着父类改一个”。
非常棒的疑问 👏👏👏 这个问题说明你已经开始真正理解 C# 的多态底层机制了。 你觉得“对象是 Dog 类型,为什么不调用 Dog 的方法?”——这个直觉没错! 但要弄清楚为什么结果不是那样,我们得看编译器是怎么决定调用哪个方法的。
让我们一步步剖析。👇
🧩 一、先看这段代码
class Animal
{
    public void Speak()
    {
        Console.WriteLine("动物在叫。");
    }
}
class Dog : Animal
{
    public new void Speak()
    {
        Console.WriteLine("狗在汪汪叫。");
    }
}
class Program
{
    static void Main()
    {
        Animal a = new Dog();
        a.Speak();   // ❓为什么输出:动物在叫?
    }
}🧠 二、从“变量类型” vs “对象类型”看区别
你认为应该执行 Dog.Speak() 是因为对象是 Dog; 但 C# 编译器在决定调用哪个方法时,还要看方法是不是 虚方法 (virtual)。
⚙️ 三、关键点:C# 的“绑定时机”
在 C# 中,方法调用有两种绑定方式:
📘 四、解释你的代码行为
在你的代码中:
public void Speak() { ... }      // 普通方法,不是 virtual
public new void Speak() { ... }  // 隐藏父类方法父类的
Speak()不是虚方法 → 静态绑定;子类用
new创建了一个新的方法,不是重写;当编译器看到
a.Speak()时,它看到的是“变量类型是 Animal”, 所以它认为“我要调用 Animal 的 Speak()”, 并且在编译阶段就确定下来了。
🧩 运行时,虽然 a 实际上指向一个 Dog 对象, 但调用哪个方法已经在编译时固定死了——不会再去检查对象类型。
💬 五、如果想要“真正的多态”,需要用 virtual/override
只要你把父类方法改成 virtual,子类用 override,结果就完全不同了:
class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("动物在叫。");
    }
}
class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("狗在汪汪叫。");
    }
}
class Program
{
    static void Main()
    {
        Animal a = new Dog();
        a.Speak();   // ✅ 现在输出:狗在汪汪叫。
    }
}现在:
Speak()是虚方法;调用绑定被延迟到运行时;
程序运行时会检查对象实际类型 → 是
Dog→ 调用Dog.Speak();✅ 真正的“运行时多态”。
🔍 六、总结对比
✅ 七、总结一句话
在 C# 中,如果方法不是
virtual的,调用哪个方法是 编译时 决定的; 如果方法是virtual的,调用哪个方法是 运行时 决定的。
所以:
Animal a = new Dog();
a.Speak();之所以调用父类方法,是因为编译器“只看到了变量类型是 Animal”, 而且 Speak() 不是虚方法,它在编译时就已经锁定父类版本。
是否希望我帮你画一张图,显示 👉 “静态绑定(new) vs 动态绑定(override)” 的执行流程对比(编译时 vs 运行时调用决策)? 这张图特别适合教学或做 PPT。