2、类和对象
2.1类的实例化
类本身是面向对象编程中的一种的统称。
下列代码中,Person是类,p是对象,前面Person p相当于定义了一个对象p 可以理解为用new创造一个新的类空间。 当需要多个空间时,就好像打包了很多的快递箱,每个箱子各自进行不同的打包内容。(包装化)
Person p = new Person()
2.2继承,是子继承父的方式
!2.2继承
继承更多用于当多个类用相同,或者相似的方法时,这时候会产生的大量冗余代码,继承可以将这些方法归纳到一个类里面,并且给这些类使用这些方法。
public class a : b{}
以上,a会继承b,b的一切a都可以随便用,但是构造函数和static都是只属于b的,需要特定写法调用,故会用public修饰符,但是这样大家都能用,所以C#有Protected保护,这是特定的修饰符,可以只让子类访问,提高安全性。
-
继承的同时,也会被父类改变,造成不可逆后果。且父类不会告诉子类自己的变化。
-
继承主要是用来消除冗余,让逻辑可以复用。 实例化的类,是继承的话,实例化子类的时候,开拓的空间也只有一个,但是是分多部分的。
-
C#和java中都是只有一个父类,能多个父类的比如:C++。 在方法中,使用this表示当前的对象,使用base表示父类部分。
-
调用实例上的某个方法 A,如果 A 调用了另一个方法 B,这时候,优先会使用 A 自身部分上面定义的 B。 如果想让 A 调用的 B 是派生类 最下面 的 B 的话,使用
virutal/override
将 B 设置为 虚函数 即可。 子类中存在的相同方法,如果不是 override 的,那么将会是 new 的。new 可以不写
2.2.1构造器 / 构造方法(重载overload):
-
构造器,是拿来给类实例化空间时,进行各种初始化的工作,顾名思义,实例化就差不多初始化好了。
-
在同一个类里面,构造器可以写很多个,但是只是方法名一样其他的参数就不一样了,这就是重载。
-
继承构造器的时候,如果不用base指定父类的构造器,那么将自动继承一个没有参数的构造器。
-
默认情况下,如果不显示继承某个类,那么会继承Object。(知识点:但可忽略,且系统默认不显示出来给咱看,故平时下意识忽略,:Object) 如果不显示父类构造器,那么会自动继承父类的无参构造器。
public Gf{
public Gf()//base() // 还有个看不见的Object类的无参构造器
{
}
}
public Ff{
public Ff()//:base()
{
}
}
2.2.2 Abstract(抽象):
-
带有修饰符Abstract抽象化的类,而且抽象类是不可以实例化使用的。
-
使用抽象方法,必须要把类也用Abstract抽象,且如果要有子类将它继承,那么必须使用override方法重写父类的抽象方法,父债子偿。
abstrack class Ab{
pulic abstrack void aa();
}
class Bb : Ab{
pulic override void aa(){
}
}
2.2.3密封类(sealed)
使用sealed修饰符,使类不可被继承
2.2.4虚方法
2.2.5分部类(partial)
让类可以写成多部分。在编译的环节,编译器将会帮助我们自动合并之后再编译。
partial class MyLove
{
public void 你想我吗()
{
}
}
partial class MyLove
{
public void 我想你()
{
}
}
虚方法是以修饰符为virtual的方法,
2.3组合
一个类包含另一个类,从而使用它的功能。
声明对象,和对类的实例化空间,将这片空间赋予给这个对象,并且对其中方法,属性,字段的调用
a a1=new a();
a.方法名();
使用new 来实例化类,并且调用其方法,属性,字段的一种写法。
在冗余的消除上,有些地方方便程度上不如继承 比如:多个类的有相同或者相似的方法的时候,方法的耦合度较高,继承在这种情况下比组合好使。 概念:当父类的大部分代码,你都需要的时候,继承比组合更适合。
在联系不是很多的情况下,只需要类的一部分代码的时候,组合会比继承更合适。
组合逻辑简单,可以灵活调用其他类里面的属性,字段,方法。 继承则考虑比较多,逻辑有时候会缠绕。
前期类少的时候,继承组合随意;到了项目大的时候,会将代码分割成很多小的代码块,联系的太多,逻辑反而不好看,组合会比继承更合适,该用哪个用哪个。
2.4静态类
使用修饰符static , 归类直接 类名.方法() 调用,无须类的实例化,
2.5封装
封装的本意是将多个项目封闭在一个事物里面,防止外界的随意访问。
常用的是,将一个或多个方法,字段,属性封闭在一个类里面
2.6静态方法
能被类直接调用,在main方法中,可使类不实例化直接使用静态的方法。
2.7属性
属性本身就是 [private Field + public Method] 一种语法糖:
-
它能减少太多冗余的模板代码;它能简化对实例中数据的可控性的访问,让代码更简洁
-
但是不要忘了,它跟 getter/setter 方法的本质是一样的。最后编译器还是将我们写的属性代码转换成了 getter/setter 方法的形式
-
也就是说
r.Width = 333
这样的属性赋值,本质就是方法调用
3、多态
3.1重载(overload)
-
重载是相同方法名之间的使用,通常是类的构造方法。
-
重载要在同一个实例空间执行。
-
重载定义是方法名相同,里面的参数不同
-
重载相同的对象调用
-
重载是编译时多态,因为基本都是构造函数重载,而构造函数则是编译时就运行
//重载overload的例子
class GrandPP
{
}
class PP : GrandPP
{
}
class You : PP
{
public You()
{
Console.WriteLine(".");
}
public You(string name)
{
Console.WriteLine(name);
}
public You(string name, string addr)
{
Console.WriteLine(name + ":" + addr);
}
}
new You();
new You("张三");
new You("张三", "湖南");
3.2重写(override)
-
重写是在继承中的父子类进行
-
重写的定义是方法名和参数都相同,但方法内容的行为不相同,进行对虚方法(virtual)的覆盖/重写
-
重写不同的对象调用
-
重写是运行时多态
//重写override的案例
class A
{
public string Name() { return "hello"; }
public virtual void Say() { Console.WriteLine(this.Name()); }
}
class B : A
{
public new virtual string Name() { return "world"; }
public override void Say() { Console.WriteLine("heihei" + Name()); base.Say(); }
}
class C : B
{
public override string Name() { return "who"; }
public override void Say() { Console.WriteLine("hahaha" + Name()); }
}
class D : C
{
public override string Name() { return "ryou"; }
}
A a = new D();
a.Say();
3.3重构(题外话,注意)
不属于编译代码,属于人实际的行为,对于杂乱且多,觉得不好的代码进行重新的构造,实际逻辑不发生改变。
3.4多态的思想
-
继承是多态的前提
-
继承中当类很多的时候,其中每个类可以有相同方法名的方法,当调用类,使用这个方法时,调用一个命令,那么各个对象其实都做对应的不同的方法内容的事。 (简单概括,不同的类使用相同方法)
4、接口(interface)
-
接口本质就是一个可以进行 多继承 的纯的抽象类。可以把它看做是继承的一种外包装
-
接口中的纯是指,接口里面只能有空的方法
-
使用 interface 关键词声明接口,接口里面只能包含方法。按照习惯,一般使用 IXxx 的方式命名接口
interface IXxx{ void a(); }
-
不需要使用 public 修饰符,因为接口里所有方法默认都是公开的。方法不需要有方法体
-
接口实际上就是一种 合同,它起到的作用是制定统一的 规则
-
接口有很多好处: 减少耦合度,也就是减少相似的代码的量。 接口只需要依靠interface,而不是实体类,故连接的类可以灵活更换或更改,更易于拓展和维护
4.1、面向接口编程
依赖于interface,而不是具体类,将它当场一个舞台,每个类想连接上去表演的时候,都需要通过它的要求,然后再表演自己的才艺,在interface的基础上在这个舞台上大家可以随意发挥,台下也可以准备;人员不满意,也就是类或者方法不满意,就把它换掉,用别的。