类Class与对象Object
- 是一种数据结构
- 是一种数据类型
- 代表现实中的“种类”
类是对一切事物的描述,是抽象的,概念上的定义 对象是实际存在的该类事物的每个个体,因而也称为实例 万物皆对象
面向对象特征
- 封装性
- 继承性
- 多态性(抽象性)
修饰符
访问修饰符
public
公有的,任何代码均可以访问,应用于所有类或成员internal
内部的,同一个程序集的对象可以访问,就是当前项目里面可以访问;不写默认就是它protected
受保护的,该类内部和继承类中可以访问。private
只有同一个类中的函数可以访问它的私有成员。protected internal
protected和internal的并集,符合任意一条都可以访问
static
静态的,表示这个属性,方法等是属于这个类的而不是对象个体。静态类不能实例化对象
public static class Test{public static string Id { get; set; }public static void Show(){Console.WriteLine("静态方法执行");}}
virtual
虚方法,写在父类的方法上,子类可以选择对这个方法就行重写。详情看本文的重写部分
override
重写方法,重写父类的virtual虚方法和abstract抽象方法。详情看本文的重写部分
abstract
随着继承越来越多,类变得越来越具体。而父类应该是一个抽象的概念,不应该有实体。
子类继承抽象基类,如果基类有抽象方法,子类不实现这个抽象方法,必然子类也是一个抽象类
namespace ConsoleApp2{//动物应该是一个抽象的概率,设置抽象类就不能实例化对象了//抽象类里面,可以正常写属性方法//如果这个类里面的属性方法加上abstract,那么这个类也必须加abstractabstract public class Animal{public string Type { get; set; }public Animal(string type){this.Type = type;}//基类里面要被重写的方法加上virtual,虚方法。public virtual void Sleep(){Console.WriteLine("动物都要睡觉");}//一个抽象方法,也可以叫纯虚方法,虚无缥缈到方法体都没有了//子类要继承这个类,必须重写抽象方法。virtual不是必须的//多态的概念//因为不知道不同的动物都吃什么,就让不同的动物子类去实现他们自己吃啥。但是作为动物,是必须要吃东西的,基类定义了一个概念,子类遵守概念拓展public abstract void Eat();}public class Cat : Animal{public Cat(string type):base(type){}//子类重写父类的抽象方法,还是用overridepublic override void Eat(){Console.WriteLine("猫吃鱼");}//子类里面重写基类方法家还是那个override,重写方法public override void Sleep(){Console.WriteLine("猫在猫窝里面睡觉");}}public class Dog : Animal{public Dog(string type):base(type){}//子类重写父类的抽象方法public override void Eat(){Console.WriteLine("狗吃肉");}public override void Sleep(){Console.WriteLine("狗在狗窝睡觉");}}}
namespace ConsoleApp2{class Program{static void Main(string[] args){Animal animal1 = new Cat("猫");animal1.Eat();//猫吃鱼}}}
如果一个抽象类里面全是抽象的东西,和接口就很像了
sealed
密封
abstract class A{public abstract string Name { get; set; }public abstract void a();public abstract void b();}class B : A{//子类不能重写这个属性了public sealed override string Name { get; set; }public override void a(){}//继承的子类无法对这个方法进行重写了,而且sealed只能用在重写的方法上面,和override一起用public sealed override void b(){}}//这个类被密封了,不能被其他子类继承sealed class C : B{public override void a(){}}
partial
一个类太长,拆分成多个类分别写。只是分别写,其实还是同一个类。举个例子,有时候系统自动生成的类的代码,给他加上partial,我自己重新写一个这个类,加上partial,在同一个命名空间下。
这就实现了,我写的部分,和系统自动生成的部分分离。
// partial1.cs:namespace CodeSamples{public partial class MyPartialClass{public int method1(int x){Console.WriteLine(x);return 0;}}}// partial2.csnamespace CodeSamples{public partial class MyPartialClass{public void method2(double x){Console.WriteLine(x);}}}// program.csstatic void Main(string[] args){MyPartialClass obj = new MyPartialClass();obj.method1(11);obj.method2(34.23);Console.Read();}
封装属性
快捷操作,点击私有字段名,Ctrl+R+E
class Person{private string name;private int age;//通过写getset方法来进行封装字段public string getName(){return this.name;}public void setName(string name){this.name = name;}}
class Person{private string name;public string Name{get{return this.name;}set{this.name = value;//用属性的方式,set里面自带的value就是给Name属性赋的值}}private int age;}
自动属性是C# 5.0(含)之后,微软新增的语法糖,全称为 Auto-Implemented Properties。如果属性的set和get访问器中没有任何逻辑,就可以使用自动实现的属性。不需要声明私有化字段。编译器会自动创建它。
class Person{public string Name { get; set; }//可以设置getset访问修饰符,还可以赋初始值public int Age { private get; set; } = 42;}
可以只写get只读属性,只写set只写属性。如果一个属性需要动态的计算出来,可以使用getset实现“计算属性”的功能
析构器
手动释放类对象资源,当类的对象用完了,没有引用的时候,就会执行析构器,释放这个对象资源
public class Animal{~Animal(){//对象没有引用时,就执行了这个析构器,释放了资源}}
继承
减少代码冗余,提高复用性。
子类继承父类,子类就拥有了父类的全部属性和方法,便于功能扩展
继承是多态的前提。
所有类都继承自Object类
子类的访问级别不能超过父类,例如,父类是internal,子类就不能是public。
base访问父类的属性,方法,构造器等
public class Animal{public string Type { get; set; }public Animal(string type){this.Type = type;}}//Cat继承了Animal,拥有了Animal的Type属性public class Cat : Animal{//当实例化子类时,会先调用父类的构造器。//默认就调用空参构造器,如果基类构造器重载了,而没有显式的写空参构造器//有两种写法①,base里面传入和基类构造器匹配的参数public Cat():base("动物"){this.Type = "猫";}//②public Cat(string type):base(type){}public void ShowType(){//base关键字访问父类,只能向上访问一层//但是这里base和this一样,因为Cat继承了Animal的Type属性Console.WriteLine(base.Type);//this就是指向当前类Console.WriteLine(this.Type);}}
重写
注意:重写(override)和重载(overload)不一样
重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作 重载:同名,不同参的方法复写,参数可以个数不同,按顺序类型不同。调用时根据传入的参数决定调用哪个方法
在C#中如果不加virtual和override,那是隐藏,不是重写。子类继承了父类的方法A,子类本身又声明了一个一模一样的方法A(方法体不一样)。执行子类的方法A会直接调用父类的方法A,子类写的被隐藏了。
public class Animal{public string Type { get; set; }public Animal(string type){this.Type = type;}//基类里面要被重写的方法加上virtual,虚方法public virtual void Sleep(){Console.WriteLine("动物都要睡觉");}}public class Cat : Animal{public Cat():base("动物"){this.Type = "猫";}//子类里面重写基类方法家还是那个override,重写方法public override void Sleep(){Console.WriteLine("猫在猫窝里面睡觉");}}
class Program{static void Main(string[] args){//虚方法和重写方法都能直接调用Cat cat = new Cat();cat.Sleep();//猫在猫窝里面睡觉Animal animal = new Animal("动物");animal.Sleep();//动物都要睡觉}}
多态
一个事物的多种形态。
现在有动物类,和各种动物的子类
public class Animal{public string Type { get; set; }public Animal(string type){this.Type = type;}//基类里面要被重写的方法加上virtual,虚方法public virtual void Sleep(){Console.WriteLine("动物都要睡觉");}}public class Cat : Animal{public Cat(string type):base(type){}//子类里面重写基类方法家还是那个override,重写方法public override void Sleep(){Console.WriteLine("猫在猫窝里面睡觉");}}public class Dog : Animal{public Dog(string type):base(type){}public override void Sleep(){Console.WriteLine("狗在狗窝睡觉");}}
我要一只动物。
只要是动物就行,要求不高,什么都可以,可以是猫,可以是狗。毕竟我只是要一只动物,猫狗都是动物,符合要求。猫狗都是动物,也就是子类,不可能我要动物,你给我个变形金刚吧,和动物不是一类啊。
动物只是一种统称,动物都是有生命的,都要睡觉,吃饭。但是不同的动物生命的形态不同,吃的东西不同,睡觉的方式不同。
这就是多态。
class Program{static void Main(string[] args){Animal animal1 = new Cat("猫");Animal animal2 = new Dog("狗");animal1.Sleep();//猫在猫窝里面睡觉animal2.Sleep();//狗在狗窝睡觉}}
为什么要用多态
一个方法,要传入一个参数。这个参数什么类型都可以。
如果我声明参数为int类型,要是传入string怎么办。要是声明参数类型为double类型,而我要传入自己写的类对象怎么搞。
我直接声明参数类型为Object,所有类的基类,想传什么类型都可以,反正都是他儿子们。
接口同理,接口和基类是兄弟,同级。
class Program{static void Main(string[] args){T(123);//这是一个System.Int32T("这是字符串");//这是一个System.StringT(new int[10]);//这是一个System.Int32[]T(new Cat("猫"));//这是一个ConsoleApp2.Cat}static void T(Object obj){Console.WriteLine($"这是一个{obj.GetType()}");}}
