类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,那么这个类也必须加abstract
abstract 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)
{
}
//子类重写父类的抽象方法,还是用override
public 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.cs
namespace CodeSamples
{
public partial class MyPartialClass
{
public void method2(double x)
{
Console.WriteLine(x);
}
}
}
// program.cs
static 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.Int32
T("这是字符串");//这是一个System.String
T(new int[10]);//这是一个System.Int32[]
T(new Cat("猫"));//这是一个ConsoleApp2.Cat
}
static void T(Object obj)
{
Console.WriteLine($"这是一个{obj.GetType()}");
}
}