面向对象
1.什么是面向对象:一种分析问题的方式
举个例子:假设计算机上的一个高级应用程序是一个一流赛车,则用传统的编程技术,这个车就是一个单元,要想改进这部车就要替换整个车,把它送回原厂,请汽车专家对其升级,或者购买一辆新车,如果使用OOP技术,只需要从厂商那里购买新的引擎,自己按照说明书换上就行了,,这里引擎就是对代码的结构化,这样就能很快的替换成新的代码(新的引擎),而不需要找厂商帮忙。而引擎创建出来可以用于其他目的,可以装在汽车,轮船,
面向对象的三大特性:封装、继承、多态
什么是类?什么是对象?区别
1)类是一种数据类型,用户自定义的数据类型
2)类的组成:字段、属性、方法、构造函数等
1)对象是具体的一个实物,是类的实例化,
2)对象具有属性(特征)和方法(动作)
2.继承:带给我们的好处
1)代码重用
2)多态(里氏替换原则LSP)(程序的可扩展性,灵活性)
Override方法重写虚方法virtual
3.修饰符访问级别:
private 只能在本类中访问
protected 当前类内部以及所有子类中(子类内部),不区分是否在同一个 程序集内
internal 在当前程序集内部可以访问,跨程序集则无法访问
【protected与internal没有可比较性】
protected internal 在当前程序集或者在子类中都可以访问
public 能在任何地方访问
4.this:
1)作为当前类的对象,可以调用类中的成员,this.成员(成员,自己)
2)调用本类的其他构造函数,:this()(调用构造函数,自己)
5.base:
1)调用父类中的成员(调用成员,父类)base点不出子类独有的成员
2)调用父类中的构造函数(调用构造函数,父类)
3)当调用从父类中继承过来的成员时候,如果子类没有重写则this.成员;
与base.成员没区别;
如果子类重写了父类成员,则this.成员调用的是子类重写以后的, base.成员;调用的依然是父类的成员
子类构造函数必须指明调用父类的哪个构造函数
6.继承的单根性:一个类只能继承一个类
继承的传递性:.ToString()方法,object(.ToString())->person继承与 object所以也就有了.ToString()方法(.ToString())->studen(.ToString())
7.构造函数特点:
1)函数名称与类名一样
2)方法没有返回值,连void都不能有
3)修饰符一般为public
4) 构造函数可以重载(方法重载)
5)构造函数的参数就是用来初始化类中成员的
类如果不手动添加构造函数的话,系统默认有一个无参的构造函数
如果添加了有参构造函数,则无参构造函数就没了,要调用必须自己写
8.父类中都是有参函数,为什么必须自己写一个无参构造函数,子类继承才不会 出错???
1)继承的时候,构造函数不能被继承
2)子类继承父类以后(子类会有一个默认的无参的构造函数)
3)子类的这个无参函数会默认调用父类的无参构造函数
4)这时由于父类都是有参构造函数,所以找不到无参构造函数,会报错
解决办法:1、在父类中添加一个无参的构造函数
2 、既然父类中都是有参数的,那么想办法去调用父类的有参的构 造函数
public Teacher(string name):base(name)
{
}
base另一个作用,调用父类的成员
9.方法的重写:一个父类的方法只有标记为virtual,在子类继承后才能用 override 对父类方法进行重写
注意:子类重写时,修饰符,返回类型,参数类型,方法名,都必须一样
静态成员和实例成员
1、静态成员只能通过 类名.* 来访问;实例成员只能通过对象名来访问
一个普通类中,既可以包括静态成员,也可以包括实例成员
2. 在静态方法中,直接访问其他成员必须也是静态的才可以
对于非静态的成员不能直接访问,要访问必须创建对象的方式来访问
3.静态类:在类前加static关键字
1)静态类中不能是声明实例成员
2)静态类的构造函数是在第一次使用静态成员前调用,并且只会调用一次
3)静态构造函数不能有访问修饰符、没有参数(默认是privatr)
4)静态类不能被继承
静态成员、静态类在程序中的任何一个地方都可以访问,不会因为超出了方法的作用域而不能访问,它们只有程序推出的时候才会释放资源
4.什么时候使用?
当多个对象共享同一个数据的时候就可以在实例类中加入静态成员
5.静态类的继承问题
1)静态类只能继承object类 不能被其他类继承
2)不能实现任何接口(接口中的成员都是实例成员)
6.sealed :密封类,不能被继承 String类
静态类的本质:abstract+sealed static
abstract 不能被实例化
sealed 不能被继承
多态(为了程序的可扩展性)
1.多态就是指不能同对象受到相同消息时,会产生不同的行为,
同一个类在不同的场合下表现出不同的行为特征
2.多态的作用:把不同的子类对象都当作父类来看,可以屏蔽不同的子类对象之 间的差异,写出通用的代码,做出通用的编程,以适应需求不 断的变化
里氏替换原则:子类可以直接转换为父类 子类->父类
父类不可以
3.多态的实现方式:
1)virtual,子类重写父类中的方法
2)abstract,子类重写父类中的方法
3)接口interface,实现接口的类,将接口中的方法实现
具体说明:
一、抽象类abstract
1.抽象类不能被实例化,可以有普通成员
2.抽象类存在的意义:
1)抽象类不能被实例化只能被其他类继承
2)继承抽象类的子类必须把抽象类中的所有抽象成员都重写(实现)
(除非子类也是抽象类)
3)抽象类就是为了重写->实现多态
二、什么是抽象类?(形象的说明光说不做)
具体的就是不能被实例化(不能new)
三、抽象类特点:
1.需要abstract关键字标记
2.抽象方法不能有人方法实现
3.抽象成员必须包含在抽象类中
4.由于抽象成员没有任何实现,所以子类不是抽象类,必须将抽象成员重写 5.抽象类不能实例化,
6.抽象类中可以包括抽象成员,可以包含具体代码的成员
7.还有抽象方法不能用static修饰
如:pubic abstract void ShowNationlity();
形象的表达:做网站的公司(抽象类) 你给我活我去开发网站,但是网站 需要一部分flash,我公司力都是程序员(抽象类中有实现的方 法)。没人会做flash(抽象方法),于是我把做flash这部分 工作给其它公司去做(重写抽象方法的类)
抽象方法(成员)不能有实现,必须被子类重写override(除非子类也是抽象类)
抽象方法(成员)的只能出现在抽象类中。
抽象类中的抽象成员不能使用private访问修饰符,可以使用其它访问修饰符
常见问题:
当鼠标放到父类上时,没有自动提示“必须实现父类中的抽象方法”,原因可 能是父类不是abstract或,父类中没有abstract成员。
4.什么时候用虚方法?什么时候用抽象方法?
虚方法:
1.父类中必须有实现。
2.子类中可以不重写。
3.虚方法可以在普通类中。(有序方法的类是可以(可能)被实例化的。 )
抽象法:
1.父类中不能有任何实现。
2.子类中必须重写(除非:子类也是一个抽象类。)
3.抽象方法必须在抽象类中。
接口实现多态
1.什么是接口?定义:interface IFlyable 一般以大写 I 开头 able结尾
1)接口就是一种规范、协议,约定好遵守某种规范就可以写通用的代码
2)定义一组具有各种功能的方法(只是一种能力,没有具体实现,像抽象方 法一样“光说不做”)
2.接口存在的意义:实现多态
作用:接口解决了类的多继承的问题
接口解决了类继承以后体积庞大的问题
接口之间可以实现多继承
3.1)接口定义一种能力
2)子类继承抽象类,实现接口
3)接口中的成员必须不能有实现
4)接口中的成员不能有访问修饰符,隐式公开
5)接口中可以有属性、方法、索引器等,但不能有字段
6)接口中的所有程序必须被子类中全部实现
形象的比喻:皮包公司(接口)。你给我活我有能力去开发网站,但是接到活 以后我公司没人会做。于是我把他交给有能力去做的人(实现功 能的类)
使用接口来实现对扩展开放,对修改关闭
例子:static void Main(string[] args)
{
//ISpeakable p1 = new Dog();
//p1.Speak();
ISpeakable p2 = CreateChatter(-1);//接口的优点。不管返回的是什么类型对象,只要能Speak就行
p2.Speak();//调用的不是ISpeakable接口的方法,而是p2指向的对象的Speak方法
Console.ReadKey();
}
static ISpeakable CreateChatter(int i)
{
if (i < 0)
{
return new Dog();
}
else if (i == 0)
{
return new Cat();
}
else
{
return new Bird();
}
}
}
interface ISpeakable//接口定义的是一种能力。
{
void Speak();
//面试题:接口中能定义什么?
//接口中可以定义方法、属性、索引器。因为属性、索引器本质上也是方法。
//接口中不能定义字段,因为字段是实现。
}
interface IFlyable
{
void Fly();
}
class Dog : ISpeakable
{
#region ISpeakable 成员
public void Speak()
{
Console.WriteLine("我是狗狗!");
}
#endregion
}
class Cat : ISpeakable
{
#region ISpeakable 成员
public void Speak()
{
Console.WriteLine("我是猫!");
}
#endregion
}
//一个类只能有一个父类
//一个类可以实现多个接口。接口只能决定能干什么,怎么干由类来实现
class Bird : ISpeakable, IFlyable
{
#region ISpeakable 成员
public void Speak()
{
Console.WriteLine("我是鸟!");
}
#endregion
#region IFlyable 成员
public void Fly()
{
Console.WriteLine("灰呀灰!");
}
#endregion
}
4.显示实现接口
1)为什么要显示实现接口?
方法重命名后的解决办法
2)显示实现接口后,只能通过接口来调用。不能通过类对象本身来调用(显 示实现的接口,查看IL是private的,防止通过类来调用)
3)什么是显示实现接口?
实现接口中的方法时用:接口名.方法名(),并且没有访问修饰符
4)显示实现接口后怎么调用?
只能通过接口变量来调用,因为显示实现接口默认是private
接口的特点总结
1. 接口是一种规范。为了多态。
2. 接口不能被实例化。
3. 接口中的成员不能加“访问修饰符”,接口中的成员访问修饰符为public, 不能修改。(默认为public)
4. 接口中的成员不能有任何实现("光说不做",只是定义了一组未实现的成员)
5. 接口中只能有方法、属性、索引器、事件,不能有“字段”。
6. 接口与接口之间可以继承,并且可以多继承。
7. 实现接口的子类必须实现该接口的全部成员。
8. 一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A ,并实现了接口IA,那么语法上A必须写在IA的前面。class MyClass:A,IA {},因为类是单继承的。
9. 当一个抽象类实现接口的时候,如果不想把接口中的成员实现,可以把该成员实现为abstract。
10."显示实现接口",只能通过接口变量来调用(因为显示实现接口后成员为 private)
使用接口的建议
1.面向抽象编程,使用抽象(父类、抽象类、接口)不使用具体
2.向上转型
3.在编程时:
1)接口->抽象类->父类->具体类->(在定义方法参数、返回值、声明变量的 时候能用抽象就不要用具体)
2)能使用接口就不用抽象类,能使用抽象类就不用父类,能用父类就不用子 类
3)避免定义"体积庞大的接口"、"多功能接口"、会造成"接口污染",只把相 关联的一组成员定义到一个接口中(尽量在接口中少定义成员,因为继承之 后子类必须全部实现,只需要满足需求就行了) 单一职责原则
4)定义多个指责单一的接口(小接口)(组合使用)(印刷术与活字印刷术)
4.扩展:为什么使用接口?(多态:编写通用代码,扩展)
使用接口的好处?(解决类的单继承问题)
什么时候使用接口?(对行为(方法)的抽象,当多个类无法抽象出 统一的父类时,当多个类无法抽象出统一的父类时,但是多个类还具 有部分相同的方法时,可以考虑用接口,当要进行多继承的时候可以 考虑接口)