数往知来C#面向对象〈三〉
C# 基础方法篇
一、复习
1)方法的重载
方法的重载并不是一个方法,实际上方法的重载就是一些不同的 方法,目的是为了方便程序员编码,所以将功能相近的方法命名相同
根据参数,编译器自动的去匹配方法体,而不需要程序员记住 的方法
--》如何判断重载写的对不对
将方法的定义拿出来,去掉修饰符,去掉方法体,去掉返回类型
int InputNum() int InputNum(int max) int InputNum(int min,int max)
-->将参数列表中的局部变量名去掉,只留参数类型
int InputNum() int InputNum(int ) int InputNum(int ,int )
二、封装
-》属性是对字段的封装
-》 方法是对过程的封装
-》类是对对象的封装(特性和功能)
-》程序集是对类库的封装
C# 基础继承篇
为什么使用继承?
-》代码的重用
-》实现多态(里氏转换)
继承中类分为父类(基类)与子类(派生类)
基类
将具有共同特征的这个类,单独写出来,称为父类(基类)
子类
继承父类所有的特征,也可以有属于自己不同的特征。
父类(基类):把这个类的对象都具有的一些特征和行为等都封装到这个类里面。
然后由这个父类派生出子类(派生类),这些子类会把父类里的特征(属性)行为(方法)等继承下来。从而实现代码的重用
例如:
class Person { string _name; int _age; char _sex; public string Name { get { return _name; } } public int Age { get { return _age; } } public char Sex { get { return _sex; } } public Person(string name,int age,char sex) { _sex = sex; _name = name; _age = age; } public void SayHello() { Console.WriteLine("大家好,我叫{0},今年{1}岁了,我是{2}生",_name ,_age ,_sex ); } } class student : Person { public student(string name,int age,char sex):base(name,age,sex) { //方法体 } public void SayHello() { Console.WriteLine("大家好,我叫{0},今年{1}岁了,我是{2}生",Name ,Age ,Sex ); } }
这里student类是person的派生类,它继承了person类的所有成员包括SayHello方法,这里Student的sayhello方法把父类的sayhello方法给隐藏了
继承的特征
-》单根性(只能继承一个基类)
-》传递性(子类可以继承基类的成员。字段、属性、方法等)
-》 派生于object根类(基于C#)(为什么要有根类?还是为了实现多态)
注意问题
-》构造方法的问题
创建对象的时候,好像是先调用子类构造方法,然后由子类再调用父类构造方法,
再调用构造方法的时候,其实默认有一个base(),调用了父类的无参构造方法
语法:
class 基类
{
//基类成员
}
class 子类:基类
{
//子类可以有自己的成员
//基类的成员也会被继承下来
}
子类于父类构造方法的执行顺序
Student student = new Student();
这里New子类对象时会先走到子类的构造方法,这里系统会默认提供一个base()无参的构造方法。如果父类中有了有参的构造方法,系统就不会再分配无参的构造方法,
此时如果子类调用父类的构造方法就会报错,因为父类的无参构造方法已经没有了。解决办法由两个
1)再手动在父类中添加一个无参的构造方法。
2)base(参数列表)传参数上去。
public student(string name,int age,char sex):base(name,age,sex) 这里不执行下面的大括号,然后base调用父类的构造方法,如果父类上面还有父类会依次往上调,
直到调到最上面的父类执行完最上面的父类构造方法然后再依次的往下执行回到这个子类,执行剩下的方法体
{
//方法体
}
this和base关键字:
this表示当前类 当前构造方法
base表示父类 父类构造方法
经典例子:
class MyClass { public MyClass():this(3) { Console.WriteLine(1); } public MyClass(int i):this(2,3) { Console.WriteLine(i); } public MyClass(int i, int j) { Console.WriteLine("{0}{1}",i,j); } } class Program { static void Main(string[] args) { MyClass myclass = new MyClass(); } }
在new对象时首先会跳到无参的构造方法,此时看到有一个this(3),不执行方法体,在本类中寻找匹配带一个参数的构造函数,然后调用,
此时又看到一个this(2,3),又在本类中寻找匹配带两个参数的构造函数,最后调用带两个参数的构造函数,执行带两个参数的方法体,
完毕之后又回到带一个参数的构造函数中执行方法体,最后再跳会无参的构造函数中执行无参的构造函数的方法体。
C# 基础多态篇
四、访问修饰符
privete 只有在本类中访问
public 任何地方都可以访问
protected 只能在当前类和子类中访问
internal 只允许在当前类中访问
protectecd internal
里氏转换
1)子类可以直接赋值给父类(子类对象可以直接转换为父类对象)隐式转换
2)如果满足第一个条件的父类对象,可以强制转换为原来的子类对象。 强制转换
强制转换可以通过 is 和 as 来判断
is:
语法 bool b=要转换的对象 is 要转换的类型
如果可以转换就会返回一个true,如果转换不合法就会返回一个false.
IS操作符很清晰,但是操作效率不高,另种方式是AS
as:
语法 要转换的类型 对象=要转换的对象 as 要转换的类型
as操作首先测试是否合法,如果合法就转换,如果不合法就返回null,null表示空引用
五、new和override
new隐藏基类方法: 前提是子类和父类的方法名参数返回值都一样,这时候写new和不写new没上面区别。
class MyBase { public void Func() { Console.WriteLine("我是父类"); } } class MySub : MyBase { public void Func() { Console.WriteLine("我是子类"); } }
这时候子类的方法会把父类的方法隐藏掉,这时候对象是什么类型就调用什么类型的方法。
override重写基类方法:子类要重写基类的方法,父类的方法必须要有virtual 表明是虚方法,可以被子类重写。
一旦父类的方法被重写,父类的方法将不复存在,调用的时候会调用重写之后的新的方法。
C# 基础关于构造方法的调用
class Person //基类人类
{
//如何在子类中访问父类的字段
//分别定义三个字段 属性
//字段的访问修饰符设定为 protected 这样在子类中便可以访问这个字段
//protected表示当前类和子类可以访问
protected string _name; public string Name { get { return _name; } } protected int _age; public int Age { get { return _age; } } protected char _gender; public char Gender { get { return _gender; } }
//写一个构造方法 将字段初始化赋值
public Person(string name, int age, char gender) { this._name = name; this._age = age; this._gender = gender; }
//定义一个无参的构造方法,这样的话子类才能调用父类的构造函数,避免子类要调用无参的构造方法时出错。
public Person() { } }
//定义一个supperman子类 继承自 person
class SupperMan : Person { //子类独有字段 特征 private string _state; public string State { get { return _state; } } public SupperMan(string name, int age, char gender, string state) //这里不写base()默认调用父类无参的构造方法,写与不写都一样 { base._name = name; base._age = age; base._gender = gender; base._state = state; //*this 是表示这是该类中的一个字段 //*base则表示这是一个从父类中继承过来的字段 //*在这里 this 与base可以不写 是写给程序员看的 } public void Hello() { Console.WriteLine("大家好,我叫{0},我的年龄是{1},我是{2}人,我的特征是{3}",Name,Age,Gender,State); } } class Program { static void Main(string[] args) { SupperMan supperMan = new SupperMan("超人", 28, '男', "内裤外穿"); supperMan.Hello(); Console.ReadKey(); } }
C# 基础构造方法篇
2)构造方法
--》没有继承关系
-》默认构造方法(无参的构造方法)
没有提供构造方法的时候, 系统自动的添加一个无参的构造方法
如果已经写了构造方法,那么系统就不会自动的添加默认的构造方法(手动添加)
-》构造方法也有重载
调用
this(当调用制定构造方法后有this的时候,会先调用this表示的重载,再调用自己的构造方法)
--》有继承关系
-》默认调用父类的构造方法
-》使用base可以指定调用父类构造方法
静态构造方法
静态构造方法从程序的开始到结束只会被调用执行一次,当new对象或者访问这个类的字段或属性等时就会调用执行,
C# 基础多态加强篇
多态实现的前提:
-》继承
-》子类父类方法名必须相同
里氏转换原则(只是实现多态的一个条件不是前提)
-》父类 父类对象=new 子类();
。。。
子类 子类对象=(子类)父类对象 必须满足上面的条件这里才能转换成功
隐藏基类的方式
只需要在子类的方法前写上new关键字即可(不写也可以,系统会自动添加)
隐藏看类型
class Person { public void SayHello() { Console.WriteLine("依依呀呀"); } } class American : Person { public new void SayHello() { Console.WriteLine("Hello"); } } class Korean : Person { public new void SayHello() { Console.WriteLine("啊你哟哈撒哟"); } }
重写基类方法
-》在父类方法前加上virtual
-》在子类方法前加上override
重写只管新
class Person { public virtual void SayHello() { Console.WriteLine("依依呀呀"); } } class American : Person { public override void SayHello() { Console.WriteLine("Hello"); } } class Korean : Person { public override void SayHello() { Console.WriteLine("啊你哟哈撒哟"); } }
二、产生随机数
Random:专门处理随机数的类。(伪随机数,其运行原理是:先得到系统的当前时间(精确到毫秒),然后根据系统的当前时间计算出一个数(就是所谓的伪随机数))
--》创建随机对象
Random r=nrw Radom();
注意: 随机数的对象不要创建在循环里 不然会得到一些重复一样的数字
-->调用Next方法的得到随机数
-》next方法有三个重载
int res=r.netx(); 产生一个非负数的随机数
int res=r.next(100); 产生一个0到99的随机数,两端可以取到
int res=r.next(2,30);产生一个2到29的随机数,两端可以取到
记录时间的类
Stopwath:
Stopwath stop=new Stopwath();
stop.start(); 开始计算
.....
stop.Stop(); 停止计算
console.writeLine(stop.Elapsed); 得到计算结果
多态:为了程序的可扩展性
-》开放封闭的原则(对扩展开放,对修改封闭)
多态的使用:
将不同的对象都当做父类来看,屏蔽掉各个对象间的不同,写出通用代码,做出通用编程,
三、抽象类
什么是抽象方法
有些时候父类的方法不需要实现
有些时候不知道怎么实现
没有方法体的方法叫做抽象方法,使用abstact修饰,
包含抽象方法的类,也必须是一个抽象类。
抽象类中可以包含非抽象成员
抽象方法的用法和虚方法的用法完全一样
不同的是他们的定义不一样,抽象类不可以实例化
抽象类存在就是为了被继承的,因此不允许定义为private.
抽象类不能实例化,比一般类多一抽象成员
抽象类与一般类有两个最大的区别
--》不能实例化
--》 具有抽象成员 ( 凡是跟方法有关的都可以抽象)
-》方法
-》属性
-》索引器(带参数的属性)
-》事件的声明(可以看做“属性”,属性石一个get set方法,事件是add remove方法)
使用抽象属性的时候,一般是抽象类提供属性以及可访问性
子类提供字段与属性的实现
public abstract string s
{
get; //这里的属性和自动属性长得很像,但是要注意他们的含义不一样,这里由abstract修饰就是告诉系统,这里是抽象方法没有方法体,所以这里不用写{}
set; //抽象属性可以只有get或set,因为他可以由构造方法给字段赋值,而自动属性是后台自动生成字段,所以自动属性的get set要成对出现
}
C# 基础重写ToString方法
四、重写ToString方法
string[] str = { "1", "2", "3", "4" }; MyClass myClass = new MyClass(); myClass.Name1 = "我是MyClass"; myClass.Name2 = "0"; myClass.Name3 = "3"; myClass.Name4 = "4"; myClass.Name5 = "5"; MyStruct myStruct; myStruct.Name = "我是MyStruct"; Console.WriteLine(str); Console.WriteLine(myClass); Console.WriteLine(myStruct);
这里打印数组和类系统会默认调用ToString()方法 任何类型都有一个ToString()方法,因为这个方法是object根类提供的,C#里所有的类都继承自object类,所以object的ToString()会被继承下来。
Reflector可以看到object的ToString()方法是个虚方法,如果子类没有重写,那么系统都会默认调用这个方法,
可以看到这个方法调用 this.GetType()方法 (获得当前实力的命名空间),然后返回
所以上面打印出来的是这个实例所在的命名空间名和实例名。
public virtual string ToString() { return this.GetType().ToString(); }
既然父类提供的是虚方法那子类就可以重写,我们可以通过子类重写ToString()方法来实现我们想要显示的内容
class MyClass { public string name1; public override string ToString() { return name1; } } class Program { static void Main(string[] args) { MyClass myClass = new MyClass(); myClass.name1 = "张三"; Console.WriteLine(myClass);//这里会显示 张三 Console.ReadKey(); } }
//本系列会持续更新。晚安!
当你无法控制自己的情绪
将时间一分一秒地花在随大流、追热点、逞能斗气、不干实事
人生就会像一架坏掉的机器,创造不出优质的产品