C#简单笔记06:抽象类,重写override,静态类,static,静态构造,单例singleton,虚方法virtual和重写override

本文介绍了C#中的抽象类和多态概念,包括抽象类的规则、静态类的使用以及静态构造方法的作用。接着讨论了单例模式的实现,强调了私有构造方法和静态实例的重要性。最后,详细比较了虚方法和抽象方法,并解释了多态的原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

抽象类和多态

抽象父类和具体子类规则

  • 抽象类必须使用abstract关键字

  • 抽象方法只能出现在抽象类中.抽象方法必须使用abstract关键字.

  • 抽象类的抽象方法不能被实现

  • 抽象类可以有非抽象普通方法

  • 抽象类的对象不能new实例化(即只有具体类的对象才能实例化)

  • 具体子类实现父类的抽象方法时需要使用override关键字

  • 多态:可以使用抽象父类的对象(抽象类不能new)引用它的具体子类对象

abstract class Food {//抽象类必须使用abstract关键字
        //抽象方法必须使用abstract关键字
        public abstract void Eaten();//抽象类的抽象方法不能实现
        public void Test() {//抽象类可以有具体方法实现
            Console.WriteLine("Food.test()非抽象的普通方法实现");
        }
    }
    class Apple : Food {
        public override void Eaten() {//子类实现抽象父类的抽象方法
            Console.WriteLine("苹果真好吃");
        }
    }
    class Drink : Food {
        public override void Eaten() {//子类实现抽象父类的抽象方法
            Console.WriteLine("饮料真好喝");
        }
    }
    class Program {
        static void Main(string[] args) {
            //Food x = new Food();//错误!抽象类不能new
            //多态:抽象父类对象引用它的具体子类对象
            Food a = new Apple();
            Food d = new Drink();

            a.Eaten();//抽象父类对象(引用子类Apple对象)调用子类Apple.Eaten()方法
            d.Eaten();//抽象父类对象(引用子类Drink对象)调用子类Drink.Eaten()方法
            a.Test(); //抽象父类对象调用自身普通方法
            Console.ReadKey();
        }
    }

静态类

堆区:存放数组,对象,字符串变量等;

栈区:自动变量,比如 int i之类;

静态区:存放静态类(的成员),全局一直存在.

常量区:存放const常量,字面值常量例如"hello"(注意不是字符串变量)

代码区:存放代码

关于静态的规则

  • 非静态类可以有静态成员:静态的字段,属性,方法-它们只能通过类(而非实例对象)调用

  • 静态类不能实例化.

  • 静态类只能有静态成员和常量,通过类调用.

    class NormalClass {
        public static double PI = 3.1415;
        public void ShowInfo(){
            Console.WriteLine("我是非静态类NormalClass的非静态方法ShowInfo()");
        }
        public static void ShowStaticInfo() {
            Console.WriteLine("我是非静态类NormalClass的静态ShowStaticInfo()方法");
        }
    }
    static class StaticClass {
        public static double PI = 3.1415;
        //public void ShowInfo(){   //错误!静态类不能有非静态(方法)成员
        //    Console.WriteLine("我是静态类StaticClass的非静态ShowInfo()方法");
        //}
        public static void ShowStaticInfo() {
            Console.WriteLine("我是静态类StaticClass的静态ShowStaticInfo()方法");
        }
    }
    class Program{
        static void Main(string[] args) {
            //非静态类直接访问静态成员,无须new1个对象
            Console.WriteLine("NormalClass.PI = " + NormalClass.PI);
            //静态类直接访问静态成员
            Console.WriteLine("StaticClass.PI = " + StaticClass.PI);

            NormalClass.ShowStaticInfo();//非静态类直接访问静态方法成员,无须new1个对象
            StaticClass.ShowStaticInfo();//静态类直接访问静态方法成员

            NormalClass nc1 = new NormalClass();
            nc1.ShowInfo();//非静态类访问非静态方法成员是通过它的实例化对象来访问的

            //StaticClass sc1 = new StaticClass();//错误!静态类无法实例化!
            //StaticClass.ShowInfo();//错误!静态类不能拥有非静态方法!
            //sc1.ShowInfo();//错误!静态类不能拥有非静态方法!更不能通过实例化对象调用!

            Console.ReadKey();
        }
    }

  • 静态构造方法不允许带参数

  • 静态构造方法前不允许有访问修饰符

  • 静态构造方法可以存在于静态类中,也可以存在非静态类中

  • 静态构造方法最多只调用1

  • 静态构造方法在第一次(仅此一次)访问类的静态static成员时(在普通类中或静态类中)第一次(仅此一次)实例化对象时调用(在普通类中),并先于其他构造方法(如果存在)调用.

  • 如果普通类拥有静态构造方法和带参数的普通构造方法,则只能new带参数的实例对象(不能new无参数实例对象);如果之前静态构造方法没有被调用,则首次new的时候先调用无参数的静态构造方法,再调用普通的带参数构造方法;第2次起再new的时候,只调用带参数的普通构造方法(因为静态构造方法最多只调用1次)

    //静态构造方法:不允许有访问修饰符,不许有参数
    public class NormalClass{//普通类
        static NormalClass() {//普通类静态构造方法
            Console.WriteLine("系统调用普通类NormalClass" +
                "的静态构造方法static NormalClass().");
        }
    }
    public static class StaticClass {//静态类
        public static double PI = 3.1415;//静态类的静态成员
        static StaticClass() {//静态类的静态构造方法
            Console.WriteLine("系统调用静态类StaticClass" +
                "的静态构造方法static StaticClass().");
        }
    } 
    public class Program
    {
        static void Main(string[] args)
        {
            //首次访问静态类的成员,
            //在访问之前系统首次(仅1次)调用静态类的静态构造方法
            Console.WriteLine("StaticClass.PI =" + StaticClass.PI);

            //首次访问普通类的静态成员或首次new1个对象,
            //系统首次(仅1次)调用静态构造方法
            NormalClass nc1 = new NormalClass();

            //第2次或第N次new对象,系统不再调用静态构造方法
            NormalClass nc2 = new NormalClass();

            Console.ReadKey();
        }
    }

归纳:

1静态类:静态构造方法用来管理静态类的初始化;

2普通类:静态构造方法用来管理普通类的静态成员(如果有)的初始化:因为普通构造方法(管理实例对象的初始化)管理不到静态成员.

单例

单例-保证程序在运行期间,一个类最多同时存在1个唯一的对象,访问对象更加方便.

如何单例

1.private构造方法-不让外界创建对象.

2.我们需要在类的内部提供1个静态private实例

3.提供获取实例的接口

    class Player {
        //玩家的属性
        public string name;
        public int hp;
        public int mp;

        //给外部提供1个获取单例实例的接口
        public static Player GetInstance() {
            if (null == _instance) {//如果实例为空
                _instance = new Player();//那就new1个实例
            }
            return _instance;//将单例实例返回给外部
        }
        private static Player _instance;//类的private静态单例:禁止外部直接访问
        private Player() { }//私有化构造方法:禁止外界new
    }
    class Program {
        static void Main(string[] args) {
            Player p1 = Player.GetInstance();//获取单例
            p1.name = "铁蛋";
            Console.WriteLine("p1名称是" + p1.name);

            Player p2 = Player.GetInstance(); //获取到的还是唯一的单例
            Console.WriteLine("p2名称是" + p2.name); //p1和p2指向同一Player对象
            Console.ReadKey();
        }
    }

虚方法

子类使用new关键字隐藏父类同名方法.

 

虚方法和抽象方法对比

1抽象方法必须在抽象类中,虚方法在非抽象的普通类中.

2抽象方法在抽象父类中不能实现.虚方法在父类中可以实现,也可以不实现(加1对内容为空的花括号即可)

3.抽象方法在非抽象子类中必须实现.虚方法在子类中可以实现override,也可以不实现(子类中可以没有这个方法).

多态--父类定义虚方法或虚属性.之后使用父类类型引用子类对象,调用子类重写override的方法和属性.

多态一句话总结:使用父类类型,调用子类对象重写的属性和方法.

    class Parent {//父类
        //属性为virtual
        public virtual string Name {
            get { return "老王"; }
        }
        public void MethodA() {
            Console.WriteLine("调用父类方法A.");
            Console.WriteLine("-----------");
        }
        //父类声明为虚方法 -- 实行多态
        public virtual void MethodB()
        {
            Console.WriteLine("调用父类(虚)方法B.");
            Console.WriteLine("-----------");
        }
    }
    class Sub : Parent {//子类
        //重写override属性 -- 多态
        public override string Name {
            get { return "老张"; }
        }
        //使用new关键字隐藏父类同名方法-子类方法替换父类方法
        public new void MethodA() {
            Console.WriteLine("调用子类方法A.");
            Console.WriteLine("----------");
        }
        //子类重写override父类同名虚方法--多态
        public override void MethodB()
        {
            Console.WriteLine("调用子类方法B.");
            Console.WriteLine("-----------");
        }
    }
    class Program {
        static void Main(string[] args) {
            //使用父类类型引用父类对象
            Parent p1 = new Parent();
            p1.MethodA();//调用了父类方法A
            p1.MethodB();//调用了父类方法B
            Console.WriteLine(p1.Name);//父类属性
            Console.WriteLine("-----------");

            //使用子类类型引用子类对象
            Sub s1 = new Sub();
            s1.MethodA();//调用了子类方法A
            s1.MethodB();//调用了子类方法B
            Console.WriteLine(s1.Name);//子类属性
            Console.WriteLine("-----------");

            //使用父类类型引用子类对象
            Parent p2 = new Sub();
            p2.MethodA();//结果是调用了父类方法A
            
            p2.MethodB();//结果是调用了子类方法B
            //↑多态↑ -- 使用父类类型引用子类对象,调用子类实现的方法
            Console.WriteLine(p2.Name);//子类属性-属性也实现多态
            Console.WriteLine("-----------");

            //使用子类类型引用父类对象
            //Sub s2 = new Parent();//错误!不能使用子类类型引用父类对象
            //s2.MethodA();//

            Console.ReadKey();

        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值