介绍面向对象思想、类与对象的理解、类的成员(字段、属性、构造函数、方法)、面向对象中封装、继承(里氏转换原则等)特性。
1、面向对象思想
(1)什么是面向对象
-> 思考方式(面向过程是解决问题的步骤、面向对象是解决方案)
-> 代理模式(找专业的人做专业的事,不是所有事都一个人实现)
(2)面向对象的三大特征
-> 封装性、继承性、多态性
(3)类与对象的理解(跟具体情况相关)
-> 类是模型、对象是产品
-> 类:是一个类型。
-> 对象:类的实例。
2、.NET Framework类库
(1)概述
->.NET Framework 包括可加快和优化开发过程并提供对系统功能的访问的类、接口和值类型。
->.类:NET Framework 提供了一组丰富的接口以及抽象类和具体(非抽象)类。可以按原样使用这些具体的类,或者在多数情况下从这些类派生您自己的类。
->接口:若要使用接口的功能,既可以创建实现接口的类,也可以从某个实现接口的 .NET Framework 类中派生类。
->.NET Framework类对象:
(A)Object:对象层次结构的根。C#数据类型为object。
(B)String: Unicode 字符的不变的定长串。C#数据类型为string。
(2)命名约定
->.NET Framework 类型使用点语法命名方案,该方案隐含了层次结构的意思。
->此技术将相关类型分为不同的命名空间组,以便可以更容易地搜索和引用它们。
->全名的第一部分(最右边的点之前的内容)是命名空间名,最后一部分是类型名。
例如:System.Collections.ArrayList表示ArrayList 类型,该类型属于 System.Collections 命名空间。该命名空间中的类型可用于操作对象集合。
(3)命名空间
System 命名空间是 .NET Framework 中基本类型的根命名空间。
此命名空间包括表示由所有应用程序使用的基本数据类型的类:Object(继承层次结构的根)、String 、Array和Int32、Char、Byte等。
3、类与对象(部分细节请参考“2.3 面向对象 静态、引用类型、引用、异常等.txt”)
(1)类的概念:
类是一个数据类型,是C# 中功能最为强大的数据类型,像结构一样,类也定义了数据类型的数据和行为。程序员可以创建作为此类的实例的对象。
与结构不同,类支持继承,而继承是面向对象编程的基础部分。
类和结构的比较:
结构与类共享大多数相同的语法,但结构比类受到的限制更多:
在结构声明中,除非字段被声明为 const 或 static,否则无法初始化。使用时所有字段要初赋值。
结构不能声明默认构造函数(没有参数的构造函数)或析构函数。(结构是值类型)
结构不能从类或其他结构继承。因为所有值类型都已继承自 ValueType,后者继承自 Object。
(2)类的定义:
从已有类派生自己的类,若没有指定父类,默认的直接继承自Object类
值类型(结构类型)定义public struct Char{}public struct Int32{}用struct关键字
引用类型(类类型)定义public sealed class String{}用class关键字
(A)用class关键字定义整个类
[访问修饰符] [abstract] class 类名 //用关键字class定义
{
// 成员(包括字段、属性、方法、构造方法、索引器、事件、委托、结构等)
}
(B)用partial class关键字定义部分类,如:
public partial class MyClass
{
string firstName;
string lastName
}
public partial class MyClass
{
int age;
int Num;
}
(3)创建类的实例
声明MyClass类型的变量(C#强类型,每个变量和对象必须具有声明的数据类型)
MyClass mc; //此时还没有实际的包含对象数据,没有指向一个对象。
创建MyClass类的新实例(对象)(使用new关键字)
将创建的实例(对象)赋给变量,完成了实例化。
mc = new Myclass(); //此处可以通过构造方法或初始化器赋初值
以上两步可以合在一起完成:MyClass mc= new Myclass();
完成对象实例化后,才是创建好了一个可用的实例,才可以访问实例中的成员。
(4)类与对象:
创建(new)一个对象的时候,系统在内存中为这个实例(对象)开辟了一块内存空间(堆),并给对象的字段赋默认初始值,为了方便访问,将能唯一标识这个对象地址的值赋给变量mc(栈),使得通过mc可以访问这个对象。
赋值之后,就用mc来指代这个对象了。所以直接说mc是MyClass类的一个对象。
以下代码中的p1和p2是相等的,可以看作是同一个对象的两个名称(正名别名)
换言之,p1和p2就是MyClass类的同一个对象!
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "佳木斯";
p1.Age = 21;
Person p2 = p1;
Console.Write(p1==p2); //打印 true
}
类是对象的模板,对象是类的实例,每个对象在与内存中开辟一块空间,各字段都有具体值的。
4、类的成员分类
实例成员:默认情况非静态(static)、非常量(const)的所有成员都是实例成员。
静态成员:static修饰的字段,属于类,不属于类的每个实例,用类名+点实现读写访问。
常量成员:const 隐式静态常量,不能修改的,用类名+点实现只读访问。
函数成员:属性(特性)、构造函数、方法、索引器、事件、委托等。
访问修饰符:成员前不写修饰符等价于private,要在类外部被访问,必须加public。
类的内部是class下面的花括号,不写public只有与main方法在一个类里才可以执行。
5、字段(访问修饰符及封装)
字段一般默认设为私有,提供属性给外界访问,在属性中可以对访问做权限限制。
封装字段生成属性快捷键:Ctrl+r,e 然后2次回车
6、属性 (分为只读属性,只写属性,可读可写属性)
(1)属性(特性)
字段需要保护起来,所以设为私有;外界需要访问的通过属性实现。
(A)属性里面包含两个部分,get,set
这两个部分分别表示:get表示返回字段的值,set表示设置字段的值。
(B)属性就是从外界访问字段的渠道。
字段用骆驼(camelCase)命名法,属性用帕斯卡(PascalCase)命名法
(C)属性可以控制外部赋值的逻辑和返回的值的逻辑。
在类的内部赋值,直接使用字段即可,如果对字段的赋值有约束筛选等判断,使用属性
(D)属性在本质上就是方法,其中get{}是一个方法,set{}是一个方法。
(E)属性不具备存储能力。
(2)自动属性
使用自动属性时,虽然没有定义字段,但是系统在后台生成了与属性对应的字段来实现存储的需要:接收赋值以及向外返回值。
针对自动属性的set和get部分,系统也生成了相应的代码来实现功能。
7、构造方法
(1)写一个类系统会自动生成(无参的)构造方法。
(2)构造方法是为了在new的时候初始化对象,给对象字段赋初值。
new Myclass()中的“MyClass()”就是在调用构造方法赋值。
(3)手动添加构造方法以后,按需要来赋初值。
系统自动生成的无参构造方法就不存在了,需手动添加无参构造方法,才不会出错。
(4)构造方法是可以重载的
附:初始化时,没有显式赋值的字段的值,数字类型 0,char ‘\0’,bool false,其他null。
8、构造方法中的this和base关键字
(1)this关键字表示对象的当前实例,base表示父类。用来指明成员所在的类。
(2)this用来调用本类构造方法,base用来调用父类构造方法。
this用法1:将当前对象作为参数传递给另一个方法
this用法2:如果实例成员中具有与形参相同的名称,使用this关键字可解决这种歧义。
public void SetName(string FirstName,string LastName)
{
this.FirstName= FirstName;
this.LastName= LastName;
}
9、封装
属性是对字段的封装
方法是对过程的封装
类是对对象的封装(特征与功能)
程序集是对类库的封装(*)
(1)封装的应用实例:建一个dll文件夹,将dll文件放进来,添加引用即可调用
注意:生成.dll类库文件,需要在新建项目的时候选择“类库”。
(2)封装的应用实例:在一个项目调用另一个项目中的方法需要注意:
(A)添加引用,导入命名空间
(B)被调用的方法所在的类需是用public修饰的。
(C)被调用的方法本身需是用public static修饰的,否则需创建类的实例调用。
(D)两个项目的类不要重名,否则就需要写全命名空间才能调用。
10、继承之里氏转换原则
第1条:子类对象可以直接赋值给类对象(子类可以隐式转换为父类)
第2条:指向子类的父类对象,可以强制转化为该子类对象
is运算符:if(对象 is 类型)与 第2条配合使用
示例:造人(Teacher、Student继承自Person类)
static void Main(string[] args)
{
Teacher t = new Teacher("胡安明",'男',23);
Student s = new Student("皓皓",'女',27,"瑜伽");
Teacher tt = new Teacher("黄小明",'男',32);
Person[] p = {t,s,tt}; //第1条 子类隐式转换为父类
for (int i = 0; i < p.Length; i++)
{
if(p[i] is Student)
{
Student s1 = (Student)p[i];
s1.SayHello();
}
else
{
Teacher t1 = (Teacher)p[i];
t1.SayHello();
}
}
}
附:C#是类型安全的语言
-> 什么类型的数据,只能赋值给什么类型的变量
-> 什么类型,只能访问该类型的成员(通过点)
附:is运算符和as运算符
对象 is 类型;//返回bool值
子类类名 变量 = 父类变量 as 子类;//转换成功完成赋值,不成功赋null。
11、继承之构造方法的执行:
new的时候调用构造方法,(其他时候不能用),执行时先去调用父类的构造方法,然后再执行子类的构造方法的方法体
->默认地调用父类的(无参)构造方法,如果父类中添加了有参的构造方法,无参构造方法就没有了。会报错!处理:给父类添加无参构造方法;
->如果要调用父类的有参构造方法,让子类指定调用父类的构造方法
//父类构造方法
public Father()
{
}
public Father(int n, string nm, char s)
{
num = n;
name = nm;
sex = s;
}
public class Son : Father
{
public static int count;
public Son(): base(11, "jam",'男') //子类构造方法,用base()调用父类的方法
{
}
}