C#oop

初识C#OOP

一,深入.NET框架

1.Microsoft .NET框架概述

2000年,微软公司向全球提供具有革命性的软件和服务平台,这对于消费者,企业和软件开发商来说,预示着个人将获得更大能力和充满更多商业机会新时代的到来。Microsoft .NET平台利用以互联网为基础的计算和通信激增的特点,通过先进的软件技术和众多的智能设备,从而提供更简单,更个性化,更有效的互联网服务。

1.1.NET框架的魅力

①提供了一个面向对象的编程环境,完全支持面向对象编程。

②对Web应用的强大支持,如今是互联网时代,大量的网络应用程序发挥着重要的作用。

③对Web服务的支持。

2.NET框架的体系结构

1.1.NET框架结构:

.NET框架运行在操作系统之上,是.NET最基础的框架,主要包含公共语言运行时(CLR)和框架类库(FCL)。

①公共语言运行时(CLR):

它是所有.NET应用程序运行时的环境,是所有.NET应用程序都要使用的编程基础,它如同一个支持.NET应用程序运行和开发的虚拟机。

它包含两个组成部分:CLS(公共语言规范)和CTS(通用类型系统)

CLS:编程语言区别不仅在于类型,语法或者语言规范都有很大的区别,CLS限制了不同点引发的互操性问题。

CTS:用来解决不同语言数据类型的不同的问题;

②框架类库(FCL)

就是指平常要引用的那些命名空间,.NET框架提供了非常丰富实用的类库。

3.面向对象回顾

1.1类和对象

类和对象有着本质的区别,类定义了一组概念的模型,而对象是真正的实体。

①由对象归纳为类,是归纳对象共性的过程。

②在类的基础上,将状态和行为实体化为对象的过程称为实例化。

属性:

①只写属性:只包含set访问器

②只读属性:只包含get访问器

③读写属性:同时包含set访问器和get访问器

private  string _name;

public string Name

{

 		get {return _name;}

​		set {_name=value;}

}

1.2封装

第一学期我们学了面向对象的三大特征之一:封装。封装又称为信息隐藏;是指利用抽象数据类型将数据和数据的操作结合在一起,使其构成一个不可分割的独立实体,尽可能隐藏内部的细节,只保留一些对外接口,使之与外部发生联系。

封装带来的好处:

①保证数据的安全性

②提供清晰的对外接口

③类内部实现可以任意修改,不影响其他类

将字段封装为属性是封装的一种方式,类的私有方法也是一种封装。

1.3类图

在软件开发中,软件的规模一般都很大,一行行阅读是非常困难的,在面向对象编程中,我们经常使用类图来解决这个问题。类图将类的属性和行为以图的行为展示出来,使读者不用阅读大量的代码就可以知道类的功能及类之间的关系。

私有成员: “—”;

公有成员:“+”;

类图是表示类的结构及类与类之间关系的图表。

二,深入C#数据类型

1.值类型和引用类型

1,值类型

值类型源于System.ValueType家族,值类型数据所在的区域称为 “栈”,只要修改它,就会在它的内存区域内保存这个值,值类型主要包括的基本数据类型 “int, float, double"和枚举类型等

2,引用类型

引用类型源于System.Object家族,在C#中引用类型主要包括 ”数组,类,接口“等

​ 数据分类

值类型 int, long, float, double, char, bool, enum, struct
引用类型 System.Object, string, class, int[]

2.1 结构

1,结构的定义:

访问修饰符  struct  结构名

{

​       //结构体

}


2,结构的定义有以下的特点:

①结构中可以有字段,也可以有方法;

②定义时,结构中的字段不能被赋初始值;

3,在使用结构时要注意以下几个方面:

①可以不用new,直接定义结构的对象即可;

②声明结构后,必须给结构的成员赋初值;

1.2装箱和拆箱

我们说数据类型按照储存方式可以分为值类型和引用类型,两者可以互相转换。

①装箱:将值类型转换为引用类型的过程叫装箱。

②拆箱:将引用类型转换为值类型叫拆箱。

static void Main(string [] args)

{

  int i=123; 

object o=i;  //装箱

int j=(int)o;  //拆箱

}

2.不同类型的参数传递

值传递和ref传递的两种方式:

①值传递:在方法中对参数值的更改在调用后不能保留;

②使用ref传递:可以保留对参数值的更改;

2.1值方式参数传递

①使用引用类型作为参数

public  void Vote(SE  se)

{

​		se.Popular++;

}

②使用值类型作为参数

2.2引用类型参数

①使用引用类型作为参数

public  void Vote(ref SE  se)

{ 

​		se.Popular++;

}

②使用值类型作为参数

小结:

使用值方式(不用ref修饰)传递值类型参数时,参数在方法中的修改不会保留;

使用值方式(不用ref修饰)传递引用类型参数时,参数在方法中的修改会保留;

使用引用方式(用ref修饰)传递值类型或引用类型参数时,参数在方法中的修改都会保留;

三,使用集合组织相关数据

1.ArrayList

ArrayList非常类似于数组,也有人称它为数组列表,ArrayList可以动态维护,一般数组的长度都是固定的,而ArrayList的容量可以根据需要自动扩充,它的索引会根据程序的扩展而重新分配调整.

ArrayList类属于System.Collections命名空间,这个命名空间包含接口和类;

​ ArrayList常用的方法和属性:

属性名称 说明
Count 获取ArrayList中实际包含的元素数
返回值类型 方法名称 说明
int Add(Object value) 将对象添加到ArrayList的结尾处
void RemoveAt(int index) 移除ArrayList指定的索引元素
void Remove(Object value) 从ArrayList中移除特定元素
void Clear() 移除所有元素

(1)给ArrayList添加数据

1,通过Add()方法可将对象添加到ArrayList的结尾处

2,返回值:值是一个int整型,用于返回所添加的元素的索引

3,如果向ArrayList中添加的元素是值类型,这些元素就会装箱处理转换为Object引用类型,然后保存;

(2)存取ArrayList中的单个元素

ArrayList获取一个元素的方法和数组是一样的,也是通过索引(index)来访问,需要注意的是,由于给ArrayList添加的元素都会被转换为Object型。

(3)遍历ArrayList中的元素

int[] array=new int[]{0,1,2,3};

for(int i=0; i

2.Hashtable

C#提供了一种称为Hashtable的数据结构,通常称为哈希表,Hashtable的结构是通过键(Key)和值(Value)来组织的

Hashtable也属于System.Collections命名空间,它的每一个元素都是一个键/值对;

​ Hashtable的常用属性和方法:

属性名称 说明
Count 获取包含Hashtable中键/值对的数目
Keys 获取包含在Hashtable中键的集合
Values 获取包含在Hashtable中值的集合
返回值类型 方法名称 说明
void Add(Object key,Object value) 带有指定键和值的元素添加到Hashtable
void Remove(Object key) 从Hashtable中移除带有特定键的元素
void Clear() 从Hashtable中移除所有元素

(1)Hashtable通过Add()方法添加元素

Hashtable的Add()方法有两个参数,一个表示键,一个表示键所对应的值;

(2)删除Hashtable的元素

通过键(Key),使用Remove()方法就可以删除Hashtable的元素;

(3)遍历Hashtable中的元素

int[] array=new int[]{0,1,2,3};

foreach(Object item in array.Keys)

{
	Console.WirteLine(item);
}

foreach(Object item in array.Values)

{
	Console.WirteLine(item);
}

3.泛型和泛型集合

泛型引入了一个概念:类型参数。通过使用类型参数(T),减少了运行时强制转换或装箱操作的风险,比较经典的泛型集合是List和Dictionary

3.1 泛型集合List

List 对象名=new List();

""中的T可以对集合中的元素类型进行约束,T表明集合中管理的元素类型;

List的使用方法和ArrayList类似,只是List无须类型转换;

​ List与ArrayList的区别:

异同点 List ArrayList
不同点 对所保存元素进行类型约束 可以增加任何类型
添加/读取值类型元素无须拆箱和装箱 添加/读取值类型元素需要拆箱和装箱
相同点 通过索引访问集合中的元素
添加元素方法相同
删除元素方法相同

3.2泛型集合Dictionary

Dictionary 对象名=new Dictionary();

说明:中K表示集合中Key的类型,V表示Value的类型,它们的含义和List是相同的;

例如:

Dictionary eng=new Dictionary();

eng集合的Key类型是string型,Value是SE类型;

​ Dictionary和Hashtable的对比:

异同点 Dictionary Hashtable
不同点 对保存元素进行类型约束 可以增加如何类型
添加/读取值类型元素无须拆箱和装箱 添加/读取值类型元素需要拆箱和装箱
相同点 通过Key获取Value
添加元素方法相同
删除元素方法相同
遍历方法相同

3,泛型类

使用泛型类,可以封装不是特定于具体数据类型的操作。定义泛型类的过程,与定义一个类相似,不同之处在于,尖括号里定义了类型参数;

public class 类名
{
	//.....
}

T指类型参数,代表具体的数据类型,可以是类类型,也可以是基本数据类型。

泛型有以下优点:

1.性能高 2.类型安全 3.实现代码的重用

四,深入类的方法

1,构造函数

我们知道要使用类的属性和方法来完成功能首要的任务是将类进行实例化,通过SE eng=new SE();这种创建类示例的方法被称为构造函数;

构造函数具有以下特点:①方法名和类名相同 ②没有返回值类型 ③主要完成对象的初始化工作

·1.1无参构造函数

在默认的情况下,系统会给类分配一个无参构造函数,并且没有方法体;

访问修饰符 类名()

{
	//方法体
}

1.2带参构造函数

一般来讲,给方法设置参数可以调整方法的行为,使方法多样化。同样,构造函数也可以接收参数,用这些参数给属性赋值。语法如下:

访问修饰符  类名(参数列表)
{
	//方法体
}


在调用带参函数时需要注意的几点:

①参数的个数要对应 ②参数的数据类型要一一对应;

2,方法重载

2.1构造函数的重载

具体来说,在面向对象的语言中,允许我们在同一个类中定义多个方法名相同,参数列表(参数个数,参数类型)不同的方法,称为方法重载;

方法重载的特点:

①方法名相同;

②方法参数类型不同或者参数个数不同;

③在同一个类中;

需注意:方法名和参数列表相同的方法,仅是返回值类型不同,不能称为方法重载。

class SE
{  
    public void Pay()
    {
        Console.WriteLine("1");
    }
    
    public void Pay(string name)
    {
        Console.WriteLine("名字是:{0}"+name)
    }
}


3,对象交互

在面向对象的世界里,一切皆为对象,对象与对象相互独立,但在一定外力的作用下,对象开始共同努力;

每个类都有自己的特性和功能,我们把它封装为属性和方法。对象之间通过属性和方法进行交互,可以认为方法的参数及方法的返回值都是对象间相互传递的信息。

就如同蚂蚁巢穴,平时蚂蚁一片安静,如果在蚁巢放置一些甜食,蚂蚁闻到,就会开始四处收集甜食,在收集甜食的活动中,有三个对象:

①蚂蚁对象

②蚁巢对象

③甜食对象

在甜食的这种外力的作用下,蚂蚁们开始行动,相互传递有甜食存在的信息,然后收集甜食,同样,在面向对象的程序中,对象与对象之间也存在着类似的关系,在外力的作用下,对象与对象之间就开始协调工作。

六,初识继承和多态

1.继承的概述

1.1 继承的概念

生活中有许多继承的例子,例如:在马路上跑的卡车,我们每天都乘坐的公共汽车,它们都是汽车,卡车有自己的特征:有货舱,有额定载重,行为是可以拉货。而公共汽车的特征:有客舱,有载客量,停靠站等,但是他们两个都有汽车的公共特征和行为:有车轮,可以行使,可以刹车。它们就是一种继承关系,卡车和公共汽车都是继承汽车。

public class Emplyee
{

}

public class SE:Emplyee //SE:Emplyee  其中“:”这种方式称为类的继承
{

}

1.2base关键字和protected修饰符

①base关键字在子类中使用,可以调用父类的属性,还可以用base关键字调用父类的方法及父类的构造函数。

public class SE
{
	public string Name{get; set;}
}
public class PM
{
	Console.WriteLine("名字是",base.Name)
}

​ 访问修饰符在哪些类中能否调用:

​ public ,private,protected的区别:

修饰符 类内部 子类 其他类
public 可以 可以 可以
private 可以 可以 不可以
protected 可以 不可以 不可以

从这可以看出来三种访问修饰符对类成员的访问限制程度:private>protected>public

1.3子类构造函数

①隐式构造函数:

1.无参构造函数:就是创建一个类,没有手写函数的时候,当前类会自带一个无参的构造函数。

②显示构造函数:

1.显示构造函数就是自己定义的一个构造函数。

特点:只要定义了一个类,如果没有手写无参构造函数,那么这个类会自带一个无参构造函数,但是只要你手写了构造函数,这个类就不会存在隐藏的无参构造函数。

2.继承的使用

2.1 继承的特性

1.继承的传递性:

在前面说的卡车和公共汽车继承汽车,也就是卡车和公共汽车都具有汽车的特征,其实卡车还可以分为小型卡车和中型卡车等等;

2.继承的单根性:

假设某个人既有程序员的天赋,又有音乐家的气质,但是在C#中是不能明确规定的,一个子类不能提示继承多个类。

C#中还有一个特殊的字符关键字 “sealed”,用它修饰的类是不能被继承的,我们称这种类为密封类。

2.2 is a 的应用

if(emp is Se)
{
	Console.WriteLine(emp);
}
if(emp is PM)
{
	Console.WriteLine(emp);
}

在上列代码中使用 is 关键字,这个关键字用来判断对象是否属于给定的类型,如果属于则返回true,否则返回false;

2.3继承的价值

①继承模拟了现实世界的关系,OOP中强调一切皆为对象,这符合我们面向对象编程的思考方向。

②继承实现了代码的重用,合理的使用继承,会使代码更加简洁。

③继承使得程序结构清晰,子类和父类的层次结构清晰。

3.多态

3.1 解决继承带来的问题

我们可以在父类和子类中定义如下的方法:

public virtual string Sayi()  //在父类中使用关键字virtual
{
	//省略方法体
}
public override string Sa()  //在子类使用时是有关键字override
{
	//省略方法体
}

像这种virtual关键字修饰的方法,称为虚方法,虚方法有方法体,语法如下:

访问修饰符 virtual 返回值类型 方法名()
{
	//方法体
}
访问修饰符 override 返回值类型 方法名()
{
	//方法体
}

父类中定义的虚方法并非必须被子类重写,在父类中可以给出虚方法的默认实现。如果子类不重写父类的虚方法,依然执行父类的默认实现,如果子类重写了父类的虚方法,执行子类重写后的方法。

3.2 什么是多态

例如:如果我们要求三种人——理发师,外科医生,和演员进行 “cut” 动作;

①理发师会开始剪头发(cut=剪);

②外科医生会在病人身体上割开一个伤口(cut=切开);

③演员会停止表演,等待导演下一步指令“咔”(cut=停止拍摄);

把三种不同职业的人看成不同的子类对象,每个对象都得到同一个消息——“cut”,这是一个生活中的多态,三种不同的对象对于同一个方法调用表现得不同的行为。

多态:按字面的意思就是 “ 多种形态” ,指同一操作作用于不同的对象时,可以有不同的解释,产生不同的执行结果。

可以使用虚方法实现多态。

七,深入理解多态

1.里氏替换和多态应用

1.1 里氏替换概述

子类对象可以赋给父类对象,也可以说子类可以替换父类,并且出现在父类能够出现的地方,且程序的行为不会发生变化,但是反过来,父类对象是不能够替换子类对象的,这种特性被称为:“里氏替换原则”;

“里氏替换原则”:是软件设计应该遵守的重要原则之一,有了里氏替换原则,才使继承复用成为可能。

1.2 is 和 as操作符的使用

is操作符用于检查对象和指定的类型是否兼容,而as操作符用于对象之间的类型转换:

if(emp[i] is SE)
{
	PM pm=emp[i] as PM;
}

先用 is 关键字判断员工类,再用 as 关键字将此员工对象转换为对应的的类。

里氏替换原则提出子类对象可以替换父类对象,在编写时以父类类型作为形式参数的方法,在实际调用时传入子类对象。

2.抽象类和抽象方法

2.1为什么使用抽象类和抽象方法

抽象方法是一个没有实现的方法,通过在定义方法时增加关键字 abstract 可以声明抽象方法,其语法如下:

访问修饰符  abstract 返回类型 方法名();

注意:抽象方法没有闭合的大括号,而是直接跟一个分号 “:”也就是说,它没有包括方法执行逻辑的方法体。

1.含有抽象方法的类必然是抽象类,同样,我们用关键字 abstract 来定义一个抽象类,语法如下:

访问修饰符 abstract class 类名{}

2.2 抽象类和抽象方法的应用

1.如何实现抽象方法

从一个抽象父类派生一个子类时,子类将继承父类的所有特征,包括它未实现的抽象方法。抽象方法必须在子类中实现,除非它的子类也是抽象类,与子类重写父类的虚方法一样,在子类中也是使用 “override”关键字来重写抽象方法。

访问修饰符 override 返回类型 方法名();

举例一个示例:

public abstract class SE
{
	public abstract void Run(); //抽象方法不能有方法体
}

public void PM:SE
{
	public override void Run(){}  //继承SE的Run方法
}

通过上面可以总结出来几点抽象方法的特点:

①在不同的类中

②有相同的方法名,相同的参数

③没有方法体

④抽象方法只能位于抽象类中

⑤父类里面的抽象方法子类必须实现,用关键字 override

3.面向对象的三大特性:

1.封装:保证对象自身数据的完整性和安全性

2.继承:建立类之间的关系,实现代码的复用,方便系统的扩展

3.多态:相同的方法调用可实现不同的实现方式

你可能感兴趣的:(C#oop)