C# 虚方法(virtual)与抽象方法 +区别+new方法隐藏 & override方法重写

一、核心知识点:虚方法 VS 抽象方法(必考对比)

虚方法和抽象方法是C#面向对象多态的核心知识点,二者核心区别清晰明确,是面试、考试高频考点,精准区分如下:

|--------|----------------------------------|-----------------------------|
| 对比维度 | 虚方法(virtual) | 抽象方法(abstract) |
| 所属类限制 | 可定义在普通类、抽象类中 | 只能定义在抽象类中 |
| 方法体 | 必须有完整方法体(有实现代码) | 无方法体(仅方法声明,以分号结尾) |
| 子类重写规则 | 可选重写:子类可重写、也可直接使用父类原方法 | 强制重写:子类必须实现所有继承的抽象方法 |
| 核心关键字 | virtual(声明)、override(重写)、new(隐藏) | abstract(声明)、override(强制实现) |

知识点总览(核心4条对比考点)

本节重点区分 虚方法 virtual抽象方法 abstract,是多态必考核心,四条规则必须完全熟记:

  1. 虚方法可以定义在普通类中,抽象方法只能定义在抽象类中。

  2. 虚方法可以有方法体(有默认实现),抽象方法不能有方法体(只有声明,无实现)。

  3. 虚方法在派生类中可以不用重写实现,抽象方法在派生类中必须强制实现。

  4. 虚方法在子类中可以配合 new(隐藏)override(重写) 使用;抽象方法只能使用 override 实现。

二、虚方法完整概念详解

1. 虚方法定义语法

在父类中使用virtual 关键字修饰的方法,称为虚方法。

语法特征:必须拥有完整方法体,自带默认业务逻辑。

2. 虚方法核心特点

虚方法存在的目的:为子类提供可选择性重写的入口,实现动态多态。

虚方法不强制子类重写:子类如果不重写,默认继承并执行父类原本的方法逻辑;子类如果重写,就覆盖父类逻辑,执行子类自定义逻辑。

3. 虚方法可存放位置

虚方法兼容性极强:既可以写在 普通类 中,也可以写在 抽象类 中。

三、案例代码父类解析(People 父类)

复制代码
public class People
{
    public string Name { get; set; }
    // 虚方法:允许子类重写
    public virtual void SayHellow()
    {
        Console.WriteLine("People打招呼");
    }
}

代码解析:

  1. People 是一个普通类,证明 虚方法可以定义在普通类中

  2. SayHellow 方法带有完整大括号方法体,拥有默认输出逻辑,符合 虚方法必须有方法体 的规则。

  3. 该方法被 virtual 修饰,所有继承 People 的子类,都可以自由选择:重写该方法 或 不重写、直接使用父类方法。


四、子类重写虚方法详解(override 用法)

1. 重写规则说明

父类虚方法,子类可以使用 override 关键字完成重写覆盖。

重写的作用:完全覆盖父类原有的虚方法逻辑,子类对象调用该方法时,优先执行子类重写后的自定义逻辑。

如果子类不写 override 重写,就默认沿用父类的 SayHellow 方法,不会报错。

2. 多个子类差异化重写(多态核心体现)

同一个父类虚方法,不同子类可以重写出完全不同的效果,这就是多态:同一个行为,不同实现

① China 子类重写
复制代码
public class China :People
{
    public override void SayHellow()
    {
        Console.WriteLine("吃了吗,抽个烟");
    }
}

中国人打招呼:重写父类方法,自定义专属逻辑。

② Japan 子类重写
复制代码
public class Japan : People
{
    public override void SayHellow()
    {
        Console.WriteLine("汪汪");
    }
}

日本人打招呼:完全不同于父类和其他子类,实现个性化重写。

③ HanGuo 子类重写
复制代码
public class HanGuo : People
{
    public override void SayHellow()
    {
        Console.WriteLine("啊你赛有");
    }
}

韩国人打招呼:独立重写逻辑,体现多态特性。


五、测试代码执行逻辑

复制代码
China c = new China();
c.SayHellow();

执行结果:吃了吗,抽个烟

逻辑解析:实例化子类对象,调用被 override 重写后的方法,直接执行子类逻辑,不再执行父类虚方法逻辑。


六、虚方法 子类两种处理方式(重点背诵)

方式1:子类不重写虚方法

子类不写 override 方法,调用方法时,执行 父类原本的虚方法逻辑,程序正常运行,无报错。

方式2:子类重写虚方法

子类使用 override 重写,覆盖父类逻辑,实现子类专属功能,是多态的核心用法。

方式3:子类使用 new 隐藏(拓展考点)

虚方法除了override,还可以用new隐藏,生成独立子类方法,不覆盖父类,属于静态绑定。


七、虚方法 VS 抽象方法 终极对比总结(满分简答题)

1. 定义位置不同

虚方法:普通类、抽象类都可以定义;抽象方法:只能定义在抽象类中。

2. 方法体不同

虚方法:有完整方法体,具备默认实现;抽象方法:无方法体,仅声明无实现。

3. 子类实现规则不同

虚方法:子类可重写、可不重写,自由选择;抽象方法:普通子类必须强制重写实现。

4. 修饰搭配不同

虚方法:支持 new 隐藏、override 重写;抽象方法:只能使用 override 强制实现。


八、核心考点总结

  1. 虚方法不强制子类重写,灵活性高,用于已有通用逻辑,子类可微调的场景。

  2. 抽象方法强制子类重写,用于没有通用逻辑,必须子类自定义实现的场景。

  3. 所有子类重写虚方法,实现不同逻辑,是典型的运行时动态多态

------------------new方法隐藏 & override方法重写------------------

一、学习前置:核心场景

本节知识点基于虚方法(virtual) 展开,仅被virtual 修饰的父类方法,子类才可以使用newoverride 改写。

重点区分两种对象接收方式(所有考题的核心场景):

  1. 向上转型 :父类变量接收子类对象 父类 变量 = new 子类();

  2. 原生接收 :子类变量接收子类对象 子类 变量 = new 子类();

二、完整分层代码案例

1. 父类代码(定义虚方法)

父类中通过virtual 定义3个虚方法,允许子类后续改写,预留多态扩展空间。

复制代码
// 父类:人类基类
public class People
{
    // 虚方法:允许子类隐藏/重写
    public virtual void Test1()
    {
        Console.WriteLine("People的Test1");
    }
    public virtual void Test2()
    {
        Console.WriteLine("People的Test2");
    }
    public virtual void Test3()
    {
        Console.WriteLine("People的Test3");
    }
}

2. 子类代码(两种改写方式对比)

子类继承父类,分别使用 new 方法隐藏、override 方法重写两种方式改写同名虚方法。

复制代码
// 子类:学生类,继承People父类
public class Student : People
{
    // new方式:隐藏父类Test1方法
    public new void Test1()
    {
        Console.WriteLine("Student的Test1");
    }

    // new方式:隐藏父类Test2方法
    public new void Test2()
    {
        Console.WriteLine("Student的Test2");
    }

    // override方式:重写覆盖父类Test3方法
    public override void Test3()
    {
        Console.WriteLine("Student的Test3");
    }
}

3. 测试调用代码(核心测试逻辑)

复制代码
class Program
{
    static void Main(string[] args)
    {
        // 1. 向上转型:父类变量接收子类对象
        People p1 = new Student();
        // 2. 原生接收:子类变量接收子类对象
        Student s1 = new Student();

        // 【new 方法隐藏】调用测试
        p1.Test1(); // 父类变量 → 执行父类方法
        s1.Test1(); // 子类变量 → 执行子类方法

        p1.Test2(); // 父类变量 → 执行父类方法
        s1.Test2(); // 子类变量 → 执行子类方法

        // 【override 方法重写】调用测试
        p1.Test3(); // 无论变量类型,执行子类重写方法
        s1.Test3(); // 无论变量类型,执行子类重写方法
    }
}

三、程序运行结果

People的Test1

Student的Test1

People的Test2

Student的Test2

Student的Test3

Student的Test3

四、new 方法隐藏 核心详解(Test1、Test2)

1. 本质

new 是方法隐藏,不会覆盖删除父类的虚方法。

相当于:子类新建了一个同名、独立的全新方法,父类原方法完整保留,父子两个同名方法互不干扰、同时存在。

2. 核心调用规则(必考死记)

new 隐藏:看【变量的类型】(编译类型)

  • 父类变量接收子类对象 → 调用 父类方法

  • 子类变量接收子类对象 → 调用 子类方法

3. 代码逻辑对应

p1.Test1() / p1.Test2():变量是父类类型,执行父类原有方法

s1.Test1() / s1.Test2():变量是子类类型,执行子类新建的隐藏方法

4. 特性总结

new 隐藏没有多态性,属于静态绑定,编译阶段就确定了调用哪个方法。

五、override 方法重写 核心详解(Test3)

1. 本质

override 是方法覆盖重写,会彻底替换、覆盖父类的虚方法。

父类原本的虚方法会被覆盖失效,程序中只会保留子类重写后的方法逻辑。

2. 核心调用规则(必考死记)

override 重写:看【对象的实际类型】(运行类型)

  • 只要 new 的是子类对象,不管用父类变量还是子类变量接收

  • 一律执行 子类重写后的方法

3. 代码逻辑对应

p1.Test3():变量是父类,但对象本质是子类 → 执行子类重写方法

s1.Test3():变量、对象都是子类 → 执行子类重写方法

4. 特性总结

override 重写具备动态多态性,属于运行期绑定,程序运行时动态判断方法。

六、new 与 override 终极对比(考试满分版)

对比维度 new 方法隐藏 override 方法重写
核心本质 子类新建独立同名方法,父类方法保留 覆盖替换父类虚方法,父类方法失效
调用依据 根据变量类型判断 根据对象实际类型判断
多态性 无动态多态(静态绑定) 实现动态多态(运行绑定)
场景特点 父子方法相互独立,互不影响 统一重写逻辑,实现多态效果

七、极简背诵口诀(做题秒杀)

new 看变量,父变父、子变子,分家两路

override 看对象,只要是子类,统统走子类

八、简答题标准答案(直接默写)

问:简述 new 隐藏和 override 重写的区别?

答:new 是方法隐藏,子类会生成独立的同名方法,父类原有方法保留,调用方法由变量类型决定,不具备动态多态;override 是方法重写,会覆盖父类的虚方法,调用方法由对象实际类型决定,无论变量类型如何,都会执行子类重写的方法,是实现动态多态的核心方式。

相关推荐
宋哥转AI1 小时前
Spring AI Graph:从0到Supervisor(二)并行执行+HITL实战
java·agent
plainGeekDev1 小时前
XML 布局 → Compose 声明式 UI
android·java·kotlin
浮游本尊1 小时前
项目全景 + 第一条完整后端链路
java·前端
jeffer_liu1 小时前
Spring AI 生产级实战:模型选择
java·人工智能·spring boot·后端·spring·语言模型·ai编程
User_芊芊君子1 小时前
【JavaEE】线程入门:线程基础 + 安全机制一次讲透
java·安全·java-ee
Ada's1 小时前
【计算机基础系列】python语言:环境搭建
开发语言·python
xiaoshuaishuai81 小时前
C# Avalonia UI的ItemControl
开发语言·ui·c#
未若君雅裁1 小时前
JMM、volatile 与 CAS:并发安全三大问题
java·开发语言
hai3152475431 小时前
# 矩阵算法·算子对齐工具 v6.1 — 技术规格与使用手册
java·开发语言·驱动开发·神经网络·spring·目标检测·矩阵