C#学习第二弹

今天来学习面向对象程序设计方法。

面向对象要先理解两个部分,第一个部分是类;第二个部分是对象。

一.类 ( 具体到抽象的过程 )

    类可以理解为一类,这一类事物具有这某种共性。比如“人”。对一个人来讲,我们可以了解他的“姓名”、“年龄”、“身高”、“体重”......等等一系列你能想到的,对应 “人” 这个类的属性。普遍来讲,这些属性加在哪一个人的身上都适用。

    类的声明很简单 使用 class 关键字 加上 类名 就可以了

举例代码

public class People
    {
        public People()
        {
        }
    }

      1.public 表示访问权限 是 public 公有

      2.class People { } 是一个类的声明 在 { } 中的则是这个类包含的方法

      3.public People ( ) { } 是这个类的构造函数(系统自动声明) 小括号 ( ) 里面是需要传递的参数,{ }里面是这个方法的具体实现。

      4.访问修饰符常用的有两个

         「1」public 公有 没有访问限制

         「2」private 私有 只有类内部成员有权访问

public class People
    {
        private string name;
        private int age;

        public People(string nameStr, int ageInt)
        {
            this.name = nameStr;
            this.age = ageInt;
        }

        public int Age
        {
            get
            {
                return age;
            }
            set
            {
                age = value;
            }
        }
    }
public static void Main(string[] args)
        {
            People memberA = new People("张三", 18);

            Console.WriteLine("get 获取年龄" + memberA.Age);
            memberA.Age = 23;
            Console.WriteLine("set 修改后,get 获取年龄" + memberA.Age);
        }

在这之中,你如果想 通过 memberA.age 来获取年龄是不可能的,因为age的访问修饰符是private。

红色区域应当注意。

二.对象 ( 抽象到具体 ) 

关键字 new

在上面的代码 Main()方法里,就实例化出了一个对象 memberA 而调用的方法是类中 构造函数的方法。


三.封装

对于封装,举一个例子。就好比你开车。你开车的时候,只需要控制方向盘,油门,刹车,就好了。你并不需要了解为什么向左打方向盘车子内部是怎么运作到轮子上,然后车向左转的。你只要明白转方向盘,车会跟着向那个方向转就好啦。

对于一个或者多个项目也是这样,程序员并不需要让人人都懂程序,只是把外部的接口交给用户(方向盘), 用户会打方向盘就好啦。这样的好处有很多。

    1.能够对类内的成员访问进行合理的控制,使得不同类之间的影响达到最低。

    2.对于封装好的模块,只要知道外部接口,以及规则就可以直接调用,省去很多些重复代码的时间,加快开发周期,提高开发效率。

注: 之所以要声明类,就是为了便于以后调用,不论是继承,还是多态,都大大提高了开发效率。


四.继承

继承就好比,师傅与徒弟的关系。师傅把自己的绝学交给了徒弟,至于徒弟怎么发挥,师傅就没有办法干涉了。同时在C#中一个徒弟只能有一个师傅。

举例代码

    public class People
    {
        protected string name;
        protected int age;

        public People(string nameStr, int ageInt)
        {
            this.name = nameStr;
            this.age = ageInt;
        }
    }

    public class Man : People
    {
        
        public Man (string nameStr, int ageInt) : base(nameStr, ageInt)
        {
            this.name = nameStr;
            this.age = ageInt;
        }

        public void Display()
        {
            Console.WriteLine("在子类man中的name是:" + this.name);
            Console.WriteLine("在子类man中的age是:" + this.age);

            Console.WriteLine("在基类people中的name是:" + base.name);
            Console.WriteLine("在基类people中的age是:" + base.age);

        }
    }
        public static void Main(string[] args)
        {
            Man memberA = new Man("张三", 18);

            memberA.Display();

        }

在上面的例子中,姓名和年龄的访问修饰符已经被我改成了protected 这是为了保证people的子类man也可以访问到这两个变量。同时在例子中标记为红色的两行代码,其实没有什么实质性的作用,删除并不影响代码的运行。同时派生类man当中的name,age两个变量的内容是存储在people类中的name,和age里面的。

在这里要注意一点

    public class People
    {
        protected string name;

        //父类无参数
        public People()
        {
            Console.WriteLine("No parameter in People");
            name = "No name input!!";
        }

        //父类有参数
        public People(string name)
        {
            this.name = name;
        }

    }

    public class Man : People
    {
        //子类无参数
        public Man()
        {
            Console.WriteLine("No parameter in man");
        }

        //子类有参数
        public Man(string name) //: base(name)
        {
            this.name = name;
        }

        public void Display()
        {
            Console.WriteLine("Name : " + name);
        }   
在这个例子中,对于People 以及Man我分别声明了两种构造函数,一种是无参数,一种是有参数。但是对与子类我并没有声明说子类去继承哪个构造函数。我们来看一下结果
        public static void Main(string[] args)
        {
            Man memberA = new Man("张三");
            memberA.Display();

            Console.WriteLine("\n************华丽的分割线****************\n");

            Man memberB = new Man();
            memberB.Display();

        }

结果

No parameter in People
Name : 张三

************华丽的分割线****************

No parameter in People
No parameter in man
Name : No name input!!

对于 memberB 来讲因为参数,所以先调用父类当中没有参数的父类构造函数,然后再调用子类当中的构造函数。

对于 memberA 来讲虽然传递了一个姓名的参数,但是派生类man还是调用父类中的无参数构造函数,也就是说如果不指定继承构造函数,子类都会默认调用父类当中的无参构造函数。

把子类有参数那里的 base 前的注释解开

        //子类有参数
        public man(string name) : base(name)
        {
            this.name = name;
        }

再运行一次,结果如下

Name : 张三

************华丽的分割线****************

No parameter in People
No parameter in man
Name : No name input!!
可见指定之后,派生类当中的构造函数就不会再去调用默认的无参数类型的构造函数了。


五.多态

在上面继承的例子中,People 的构造方法分别定义了两个,这就是一种多态的体现。

    1.方法的多态:函数名相同,但是参数类型或是参数个数不同,这叫做函数重载。这方面不过多介绍,但是要注意当两个方法的方法名、参数类型、参数数量都相同的时候,只有返回值类型不同是不可以的。

    2.类的多态:类的多态就好比,一个师傅下面有n多个徒弟,徒弟与徒弟之间平起平坐,不分大小。

举例代码

    public class People
    {
        protected string name;
        protected int age;

        public People(string name, int age)
        {
            this.name = name;
            this.age = age;
        }

        public virtual void Display()
        {
            Console.WriteLine("The name is: " + name);
            Console.WriteLine("The age is: " + age + "\n");
        }

    }

    public class Male : People
    {
        public Male(string name, int age) : base(name, age)
        {}

        //public override void Display()
        //{
        //    Console.WriteLine("This man's name is : "  + name);
        //    Console.WriteLine("He's {0} years old \n" , age);
        //}

	}

    public class Female : People
    {
        public Female(string name, int age) : base(name, age)
        {}

		//public override void Display()
        //{
        //    Console.WriteLine("This woman's name is : " + name);
        //    Console.WriteLine("She is {0} years old \n" , age);
        //}

	}

        public static void Main(string[] args)
        {
            People memberA = new People("张三" , 20);
            People memberB = new Male("李四" , 21);
            People memberC = new Female("王五" , 23);

            memberA.Display();
            memberB.Display();
            memberC.Display();
        }

结果如下

The name is: 张三
The age is: 20

The name is: 李四
The age is: 21

The name is: 王五
The age is: 23

红色部分是需要重点关注和理解的地方。

划掉注释,运行结果如下

The name is: 张三
The age is: 20

This man's name is : 李四
He's 21 years old 

This woman's name is : 王五
She is 23 years old 

在上面声明的三个变量都是People类,然而用new 进行实现的时候就出现了不同。

同样一个方法,在People里面进行了 虚方法( virtual )声明,以及实现。在他的派生类里面进行了重写  override 。当子类没有该方法的时候,实例化出来的对象就不会在new出的派生类当中。

注:「1」如果People类里面没有Display()这个方法,实例化出来的对象是不能够调用的,不论子类是否进行了声明。

      「2」因为声明的People类 所以它的派生类(Male Female)里面独有的方法 那个声明对象是不能调用的。


    3.关键字 

        「1」is is关键字用来判断某个对象是否属于某个类,返回类型为bool变量 ,在上面代码的基础上在添加这么几行

            bool BIsPeople = memberB is People;
            bool BIsMale = memberB is Male;
            bool BIsFemale = memberB is Female;
            Console.WriteLine("memberB is People? The answer is " + BIsPeople);
            Console.WriteLine("memberB is Male? The answer is " + BIsMale);
            Console.WriteLine("memberB is Female? The answer is " + BIsFemale);

结果如下

memberB is People? The answer is True
memberB is Male? The answer is True
memberB is Female? The answer is False

通过结果我们可以观察到 memberB 即使 People 类,又是 Male 类。

       「2」as as关键字用于类与类之间的类型转换,当然如果类与类之间不能转换的时候,会返回null

    public class Male : People
    {
        public Male(string name, int age) : base(name, age)
        {}

        public override void Display()
        {
            Console.WriteLine("This man's name is : "  + name);
            Console.WriteLine("He's {0} years old \n" , age);
        }

        public void MaleText()
        {
            Console.WriteLine("This method is male's.");
        }
    }
        public static void Main(string[] args)
        {
            People memberA = new Male("张三" , 18);
            Male memeberB = new Male("李四" , 20);

            //memberA.MaleText();
            //memeberB.MaleText();

            People memberA_01 = memberA as People;
            People memberB_01 = memeberB as People;
            Female memberB_02 = memberB_01 as Female;

            Console.WriteLine(memberA_01 != null);
            Console.WriteLine(memberB_01 != null);
            Console.WriteLine(memberB_02 != null);

           
        }

结果如下

True
True
False

可见,只要是用 is 关键字判断为true的,就可以用 as 进行类型转换。

as 进行类型转换的时候,不会因为转换不了系统崩掉,而是会返回一个null.只要合理利用,就可以减少代码开发出现bug的程度,同时缩短运行时间。

这方面理解的还不是很透彻,欢迎大家在评论区进行讨论。

你可能感兴趣的:(C#语言学习)