深入.NET平台和C#编程1-6
一、深入.net框架
1.1、Microsoft .NET介绍
1、.NET框架结构
.NET框架运行在操作系统之上,是.NET最基础的框架。它提供了创建,部署和运行.NET应用的环境,主要包括含公共语言运行时(CLR)和框架类库(FCL),并且支持多种开发语言。CLR是.NET框架的基础。
2、CLR
CLR全称公共语言运行时,由两部分组成:CLS(公共语言规范)和CTS(通用类型系统)
1、CLS(公共语言规范)
编译语言的区别不仅在于类型、语法或者说语言规范也有很大的区别,CLS是一种最低级的语言标准,它制定了一种以.NET平台为目标的语言所必须支持的最小特征,以及该语言与其它的语言之间实现互操作性所需要的完备特征。
2、CTS(公共语法规范也称为通用类型系统)
通用类型系统(CTS)用于解决不同语言数据类型不同的问题,如C#中的int,VB.NET中的整型是integer,通过CTS,我们把他们两个编译成通用的类型Int32;所有的.NET语言共享这一类型系统。在它们之间可以实现无缝互操作。
3、MSIL
MSIL是微软中间代码,它由JIT编译器转换成机器代码。
中间代码的出现是为了实现跨语言开发和跨平台的战略目标,.NET所有编写的应用都不编译成本地代码,所以出现了中间代码。
3、FCL(框架类库)
.NET框架另外一个重要的部分是FCL(框架类库),框架类库是一些已经被封装好的功能集合;像System.Data.SqlClient和System.Data;在WinForms应用程序开发中我们用到过System.Windows.Forms;FCL提供了对系统功能的调用,是建立.NET应用程序,组件和控件的基础。
1.2、回顾类和对象
1、类和对象
类和对象的关系:类是对象的抽象化,对象是类的实例化;
类的属性:get 和 set
1、只写属性:只有set访问器
2、只读属性:只有get访问器
3、读写属性:同时存在get访问器和set访问器
类的三大特性:封装(将内部代码私有化)、继承(子承父)、多态(一件事物的多种形态)
2、封装
1、封装概念
封装又称之为信息隐藏,是指利用抽象数据类型将数据和数据的操作结合在一起,使其构成一个不可分割的独立实体,尽可能的隐藏内部细节,只保留一些对外接口,使之与外部发生联系
2、封装的优点
1)、保证数据的安全性。
2)、提供清晰的对外接口。
3)、那内部实现可任意修改,不影响其它类。
注意:将字段封装为属性是封装的一种方式,类的私有方法也是一种封装,封装的范围不仅限如此。
3、类图
1、类图的作用
类图将类的属性和行为以图的形式展现出来,是读者不用阅读大量代码即可明白类的功能和类之间的关系。
2、类图的图标
类中的成员在图中都用不同的图标表示。私有成员会在图标的右下方有一个“小锁”。字段属性放在方法前面,变量类型和返回值放在冒号后面,而私有成员前面加一个减号"-",公有成员前面再加一个加号"+"。
二、深入C#数据类型
2.1、值类型和引用类型
1、值传递
1、值类型属于System.ValueType命名空间,存储在栈中;值类型只要包括基本数据类型和枚举类型;这里还要介绍一种数据类型:结构:struct。
2、值传递的特点:
1、值传递,传递的是基本数据类型时,形参所作修改不会影响实参;
举例:
//在类中的方法
public static void Run(int a) //形参
{
a = 100;
}
public static void Main(string[] args)
{
int a = 0;
Run(a); //实参
Console.WriteLine(a);
}
//最后输出a的值为0;
2、值传递,传递的是引用数据类型时,形参所做修改会影响实参;
举例
//在类中的方法
public static void Run(int[] a)//形参
{
a[0] = 100;
}
public static void Main(string[] args)
{
int[] a = {1,2};
Run(a); //实参
Console.WriteLine(a[0]);
}
//最后输出a的值为100;
2、引用传递
1、引用类型属于System.Object命名空间,存储在堆中;引用类型主要包括数组、类、集合、接口;引用传递又称为地址传递;
2、引用传递的特点:引用传递要在形参和实参前面加ref,并且形参所做修改会影响实参。
举例:引用数据类型的引用传递
//在类中的方法
public static void Run(ref int[] a)//形参
{
a[0] = 100;
a = new int[5];
}
public static void Main(string[] args)
{
int[] a = {1,2};
Run(ref a); //实参
Console.WriteLine(a[0]);
}
//最后输出a的值为100,并且数组的长度为5
基本数据类型的引用传递
//在类中的方法
public static void Run(ref int a)//形参
{
a = 100;
}
public static void Main(string[] args)
{
int a = 0;
Run(ref a); //实参
Console.WriteLine(a);
}
//最后输出a的值为100;
3、数组复制
数组的复制可以利用循环实现;设两个数组array1和array2(array2的长度不小于array1的长度),将数组array1中的元素的值复制到array2中。可以利用以下代码实现:
for(int i = 0;i < array1.Length;i++)
{
array2[i] = array1[i];
//将数组array1中的元素的值复制到array2中
}
4、结构:struct
结构是一种基本数据类型,结构和类相似,
语法:
访问修饰符 struct 结构名
{
//结构体
}
结构的定义和特点
1、结构中可以有字段,也可以有方法;
2、定义时,结构中的字段不能被赋初值;
3、结构使用时,可以不用new,直接定义结构的对象就可以了;
4、声明结构的对象后,必须给结构的成员变量赋初值;
结构的注意点:
1、结构不能手写无参构造函数;
2、结构里有多少个字段,定义构造函数式就要有多少个参数
5、装箱和拆箱
装箱:将基本数据类型转化为引用数据类型
拆箱:将引用数据类型转化为基本数据类型
举例:
static void Main(string[] aegs)
{
int i = 123;
object o = i; //装箱
int j = (int)o; //拆箱
}
三、使用集合组织相关数据
3.1、集合
1、集合的概念
集合就是用来存储长度不固定的一连串数据,并且具有一定的逻辑性和数据存储结构。集合分为泛型集合和非泛型集合。
2、ArrayList
ArrayList非常类似数组,称为数组列表;ArrayList可以动态维护,ArrayList提供了一系列方法对其中的元素进行访问、增加和删除的操作。
ArrayList类属于System.Collections命名空间,这个命名空间包含接口和类;
定义ArrayList的语法
using System.Collections; //命名空间
//创建容量为0的ArrayList对象
ArrayList stu = new ArrayList();
//创建容量为5的ArrayList对象
ArrayList teach = new ArrayList(5);
注:ArrayList是动态可维护的,所以定义时可以指定容量,也可以不指定容量。
ArrayList的常用方法及属性表
属性名称 | 说明 |
---|---|
Count | 获取ArrayList中实际包含的元素数 |
返回值类型 | 方法名称 | 说明 |
---|---|---|
int | Add(Object value) | 将对象添加到ArrayList的结尾处 |
void | RemoveAt(int index) | 移除ArrayList中指定下标的元素 |
void | Remove(Object value) | 移除ArrayList中特定的对象 |
void | Clear() | 清空 |
ArrayList中也有下标,也称为索引,下标从0开始;
举例:
static void Main(string[] args)
{
ArrayList arraylist = new ArrayList();
arraylist.Add("人间");
arraylist.Add(2310);
arraylist.Add(3.14);
arraylist.Add("bu zhi de");
//上面是用Add方法添加元素,并且添加的元素不是同一数据类型
arraylist.RemoveAt(2);
//删除下标为2的元素,也就是3.14
arraylist.Remove(2310);
//删除对象名为2310的元素
//遍历方法一
for(int i = 0 ;i <arraylist.Count; i++)
{
Console.WriteLine(arraylist[i]);
}
//遍历方法二
foreach(Object obj in arraylist)
{
Console.WriteLine(obj);
}
//清空
arraylist.Clear();
}
注意:在删除一个元素之后,后面的元素会自动向前移,所以注意不要数组越界了。
3、Hashtable
Hashtable数据结构,通常称为哈希表,Hashtable的数据结构是通过键(Key)和值(Value)来组织的;Hashtable也属于System.Collections命名空间,并且它的每个元素都是一个键/值对。
Hashtable常用的方法和属性表
属性名称 | 说明 |
---|---|
Conut | 获取Hashtable中键/值对的数目 |
Keys | 获取Hashtable中键的集合 |
Values | 获取Hashtable中值的集合 |
返回值类型 | 方法名称 | 说明 |
---|---|---|
void | Add(Object key,Object value) | 添加带有指定键和值的元素到Hashtable中 |
void | Remove(Object key) | 移除Hashtable中带有特定键的元素 |
void | Clear() | 清空 |
注:这里键是唯一的,并且不可以用null作为键。
举例:
//SE类中写字段和属性
public class SE
{
public SE(){} //无参构造函数
//字段
private string name; //姓名
private int age; //年龄
private string id; //学号
//属性
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
public string Id { get => id; set => id = value; }
}
//在Main方法中调用
static void Main(string[] args)
{
Hashtable hash = new Hashtable();
SE se = new SE(); //初始化一
se.Name = "人间";
se.Age = 25;
se.Id = "211";
SE joe = new SE(); //初始化二
joe.Name = "鲸落";
joe.Age = 20;
joe.Id = "110";
SE ema = new SE();
ema.Name = "赤怜";
ema.Age = 18;
ema.Id = "120";
//用Add添加三个元素
hash.Add(se.Id,se);
hash.Add(joe.Id,joe);
hash.Add(ema.Id,ema);
//删除一个元素,删除一个键是211的对象
hash.Remove("211");
//遍历键
foreach(Object obj in hash.Keys)
{
Console.WriteLine((string) obj);
}
//遍历值
foreach(Object obj in hash.Values)
{
SE se = (SE)obj;
Console.WriteLine(se.Name);
}
//遍历方式三
foreach(DictionaryEntry en in hash)
{
Console.WriteLine(en.Key); //输出键
Console.WriteLine(((SE) en.Values).Name); //输出值
}
//清空
hash.Clear();
}
DictionaryEntry是一个结构,定义可设置或检索的Hashtable的键/值对;具体可以通过查阅MSDN了解;
3.2、泛型和泛型集合
泛型:泛型引入一个概念:类型参数。
泛型集合比较经典的有两种List<T>和Dictiona<T>,"<T>"可以对集合中的元素类型进行约束,T表示集合中管理的元素类型。
1、List <T>
1、List泛型集合和ArrayList集合差不多,当也是有区别的;List泛型集合的命名空间是:System.Collections.Generic;这个命名空间定义了许多的泛型集合类;
2、List泛型集合的语法:
List<T> 对象名 = new List<T>();
3、List泛型集合和ArrayList集合的区别
1)、ArrayList可以添加任意类型的元素,List不可以,List会对数据类型进行约束
2)、ArrayList在添加/读取值类型元素时要拆箱和装箱,List在添加/读取值类型元素时不需要拆箱和装箱
3)、ArrayList和List的通过索引访问元素、添加方法、删除方法和遍历方法都是一样的。
举例:
//SE类中写字段和属性
public class SE
{
public SE(){} //无参构造函数
//字段
private string name; //姓名
private int age; //年龄
private string id; //学号
//属性
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
public string Id { get => id; set => id = value; }
}
//在Main方法中调用
static void Main(string[] args)
{
List<SE> list = new List<SE>();
SE se = new SE(); //初始化一
se.Name = "人间";
se.Age = 25;
se.Id = "211";
SE joe = new SE(); //初始化二
joe.Name = "鲸落";
joe.Age = 20;
joe.Id = "110";
SE ema = new SE(); //初始化三
ema.Name = "赤怜";
ema.Age = 18;
ema.Id = "120";
//用Add添加三个元素
list.Add(se);
list.Add(joe);
list.Add(ema);
//删除一个元素,删除一个键是211的对象,也就是初始化一se,se后面的元素会往前移
list.Remove("211");
//删除一个元素,删除下标为1的元素,也就是初始化三ema
list.RemoveAt(1);
//遍历方法一
for(int i = 0 ;i <list.Count; i++)
{
Console.WriteLine(list[i]);
}
//遍历方法二
foreach(SE obj in list)
{
Console.WriteLine(obj);
}
//清空
list.Clear();
}
2、Dictionary<K,V>
1、Dictionary和Hashtable差不多,Dictionary编译时检查类型约束,获取元素时无须类型转换,Dictionary也是通过Key/Value(键/值)对元素进行保存。
2、Dictionary<K,V>的语法:
Dictionary<K,V> 对象名 = new Dictionary<K,V>();
说明:K表示集合中Key的类型,V表示Value的类型集合。
3、Dictionary和Hashtable的区别
1)、Hashtable可以添加任意类型的元素,Dictionary不可以,Dictionary会对数据类型进行约束
2)、Hashtable在添加/读取值类型元素时要拆箱和装箱,Dictionary在添加/读取值类型元素时不需要拆箱和装箱
3)、Hashtable和Dictionary的通过索引访问元素、添加方法、删除方法和遍历方法都是一样的。
举例:
//SE类中写字段和属性
public class SE
{
public SE(){} //无参构造函数
//字段
private string name; //姓名
private int age; //年龄
private string id; //学号
//属性
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
public string Id { get => id; set => id = value; }
}
//在Main方法中调用
static void Main(string[] args)
{
Dictionary<string,SE> dic = new Dictionary<string,SE>();
SE se = new SE(); //初始化一
se.Name = "人间";
se.Age = 25;
se.Id = "211";
SE joe = new SE(); //初始化二
joe.Name = "鲸落";
joe.Age = 20;
joe.Id = "110";
SE ema = new SE();
ema.Name = "赤怜";
ema.Age = 18;
ema.Id = "120";
//用Add添加三个元素
dic.Add(se.Id,se);
dic.Add(joe.Id,joe);
dic.Add(ema.Id,ema);
//删除一个元素,删除一个键是211的对象
dic.Remove("211");
//遍历键
foreach(string obj in dic.Keys)
{
Console.WriteLine((string) obj);
}
//遍历值
foreach(SE obj in dic.Values)
{
Console.WriteLine(se.Name);
}
//遍历方式三
foreach(KeyValuePair<string,SE> en in dic)
{
Console.WriteLine(en.Key); //输出键
Console.WriteLine(en.Values.Name); //输出值,这里不需要类型转换
}
//清空
hash.Clear();
}
KeyValuePair<TKey,TValue>是 一个泛型结构,定义可设置或检索的键/值对,具体可以通过查阅MSDN了解;
3、泛型类
定义泛型类的过程和定义一个类相似。不同的是尖括号里定义了类型参数;
1、语法:
public class 类名<T>
{
//……
}
说明:T指类型参数,代表具体的数据类型,可以是类类型,也可以是基本数据类型;泛型类支持任意的数据类型。
2、泛型类优点
1)、性能高
2)、类型安全
3)、实现代码重用
举例:
class ComboBoxItem<T>
{
private string _itemText; //显示文字
public string ItemText
{
get{return _itemText;}
set{_itemText = value;}
}
private T _itemValue; //实际的对象
public T ItemValue
{
get{return _itemValue;}
set{_itemValue = value;}
}
}
四、深入方法的类
4.1、构造函数
1、构造函数是什么,用来干什么
用来创建类实例的方法称之为构造函数;构造函数主要是用来new对象的,构造函数还有一个兼职是:给成员变量赋值;
2、构造函数的特点
类的构造函数是类中一个特殊的方法,它的特点如下:
1、方法名和类名一致;
2、没有返回值类型;
3、主要完成对象的初始化工作;
3、构造函数的分类
构造函数的分类主要分为两种:显示分类和参数分类
1、显示分类:
显式构造函数:手写的构造函数
隐式构造函数:在没有手写构造函数时,系统会给一个默认的无参构造函数,这就是隐式构造函数。
2、参数分类:
无参构造函数:小括号里面不带参数
无参构造函数语法:
访问修饰符 类名()
{
//方法体
}
有参构造函数:小括号里带参数
有参构造函数语法:
访问修饰符 类名(参数列表)
{
//方法体
}
参数列表一般用来给类的属性赋值。
4.2、方法重载
1、方法重载
多态的实现方式为:重载和重写
重载和重写的区别:重载是在同一个类中;重写是在不同类中。
重载方法概念:多个构造函数提供了多种实例化一个类的方法就是方法重载;
重载的意义:为解决方法名不足;
2、方法重载的特点
1、在同一个类中;
2、方法名相同;
3、方法的参数的不同:参数的数据类型不同或参数个数不同;
注:不可以以方法的返回值类型的不同来判断是否是重载,也不可以以方法的访问修饰符的不同来判断是否是重载。
3、方法重载的实例
public static void Main(string[] args)
{
Console.WriteLine(8); //一个参数,int类型
Console.WriteLine(10.83); //一个参数,double类型
Console.WriteLine("HelloWord"); //一个参数,string类型
Console.WriteLine("HelloWord,{0}",name);
//两个参数,string类型,变量
}
重载方法的调用规则:根据参数[个数+数据类型]调用
//假设有一个Stu类,重载方法
public string Run(string name)
{
return "这是一个参数的,string类型的";
}
public int Run(int a,int b) //这是两个参数的,int类型的
{
int num = a+b;
return num;
}
//在Main方法里调用
public static void Main(string[] args)
{
Stu stu = new Stu();
Console.WriteLine(stu.Run(10,20)); //输出结果:30
Console.WriteLine(stu.Run("狗子")); //输出结果:这是一个参数的,string类型的
}
4.3、对象交互
1、概述:在面向对象的世界里,一切皆为对象。对象与对象相互独立,互不干涉,但在一定外力的作用下,对象开始共同努力。
2、交互图:
3、举例:顾客点菜
1、顾客对象顶了菜单对象,并选中服务员对象为自己服务
2、服务员对象将菜单信息告诉厨师对象
3、厨师对象根据菜单做菜,做完菜
4、厨师对象通知服务员对象菜做完了,服务员对象取菜送给顾客对象。
上面有四个对象,顾客、菜单、服务员、厨师,上面的过程就是对象的交互;
五、初识继承和多态
5.1继承概念
1、移除类的冗余代码
1、冗余代码:两个或两个以上的类有完全相同的属性;以前就是会两个类单独写属性,这样不利于代码的复用。
解决冗余代码:新建一个公共类,将其他两个类的相同部分抽取出来,放到公共类里面;在使用公共属性时要使用到继承;要将公共类作为父类,其他两个类作为子类;
2、继承的概念:被继承的类称之为父类或基类,继承的类称之为子类或派生类;继承时使用已经存在的类的定义作为基础新建类的技术,新类的定义可以直接增加的数据或新的功能,也可以用已存在的类的功能。
继承的语法:
public class B:A
{
//A类就是父类
//继承要用 ( :)来表示
}
2、base关键字和protected修饰符
1、base:base表示父类,可以用于访问父类的成员;像调用父类的属性、方法是可以的;base关键字还可以调用父类的构造函数;
base调用构造函数有两种:
1、 :base() 这是调用父类无参构造函数 ;
2、:base(参数列表) 这是调用父类的有参构造函数;
注:base可以访问父类所有的非private成员;
2、访问修饰符
访问修饰符:private(私有的)、protected(受保护的)、public(公开的)
在继承中这三个访问修饰符有不同程度的访问限制
private:在父类中用private修饰的,只能在本类中使用;
protected:在父类中用protected修饰的,可以在本类中和继承该类的子类中使用;
public:在任何一个类中都可以使用。
3、子类构造函数
1、隐式调用父类的构造函数
在默认的情况下,子类会先调用符类的无参构造函数,然后再调用子类的构造函数;这是因为说明调用的是哪一个构造函数,所以系统隐式调用父类的无参构造函数;
2、显示调用父类的构造函数
调用父类的有参构造函数,可以使用::base(参数列表),这要就可以调用指定的有参构造函数了。这样就可以实现继承属性的初始化。
5.2继承的特性
1、继承的特性
继承有两个特性:传递性和单根性;
1、传递性:传递性就像是孙子会遗传爷爷的基因一样,假设 B:A,C:B,这两组继承,B会继承A的基因,C会继承B的基因,那么C会继承A的部分基因;
2、单根性:单根性就像是一个人只能由一对亲身父母一样,一个子类只能由一个父类,但是可以有多个接口,就像一个人可以有多个干爹干妈一样;
注:C#中还用一个特殊的关键字 sealed,使用这个关键字修饰的类是不能被继承的,这种类也称为密封类。
2、is a 的应用
1、is a :is a是用来判断真正的数据类型的,is a属于bool类型;
语法:引用名(或者是对象名) is 数据类型
这里通常用于方法重写时,来判断调用哪一个类的方法;
2、还有一个 as a,as a:是用来强转的。
语法:数据类型 变量名 = 对象名 as 数据类型
3、继承的价值
1、继承模拟了现实世界的关系,OOP中强调一切皆对象;
2、继承实现了代码的重用,合理的使用继承,会使代码更加简洁;
3、继承使得程序结构清晰,子类和父类的层次结构清晰,最终的目的是使子类只关注子类的相关行为和状态,无须关注父类的行为和状态。
5.3多态
1、解决继承带来的问题
我们在遍历方法时会使用到is a ,方法不多还好,方法多了就每次都要判断就会很麻烦,也会增加代码的负担;
要解决这个问题就要用到虚方法;
1、虚方法:用virtual修饰,子类用override声明
语法:
父类:访问修饰符 virtual 返回值类型 方法名()
{
//方法体;
}
子类:访问修饰符 override 返回值类型 方法名()
{
//方法体;
}
像这种通过override关键字来修饰的方法就是重写;使用虚方法就无须考虑子类是什么类型的了。
虚方法的特点:
1、相同的方法名,相同的参数,在不同类中;
2、不强制子类实现父类中virtual方法;
3、virtual方法一定要有方法体;
2、实现多态
1、实现多态的方法:重载、重写(虚方法和抽象方法);
父类中用virtual修饰的方法称为虚方法;子类用override修饰方法来实现方法的重写;
2、定义父类变量,用子类对象初始化父类变量;
六、深入理解多态
6.1里氏替换原则
1、概念:原则上子类对象可以赋给父类对象,也可以说子类代替父类并出现在父类能够出现的任何地方,且程序不会受影响,但是反过来父类对象不能替代子类出现,这就是里氏替换原则;简单来说就是,子类可以替代父类,但是父类不能替代子类。
2、is 和as的使用:is是用来检查对象和指定的数据类型是否兼容的,as是用来两个类之间的数据类型转换;
注:用as操作符进行类型转换时不会产生异常,但是这并不代表不需要异常处理。
6.2、抽象类和抽象方法
1、抽象类和抽象方法的使用
1、抽象方法:抽象方法是一个没有实现的方法,通过在定义方法时增加关键字abstract可以声明抽象方法。
语法:访问修饰符 abstract 返回值类型 方法名();
注:抽象方法没有方法体,也就是没有大括号,直接在小括号后面跟分号(;);
2、抽象类:含有抽象方法的类就是抽象类,定义抽象方法和定义抽象类是一样的;但抽象类是定义类;
语法:访问修饰符 abstract class 类名{}
注:抽象类提供抽象方法,这些方法只有定义,如何实现都是由抽象类的非抽象子类完成。
2、抽象方法和抽象类的应用
1、如何在子类中实现抽象方法
一旦确认继承关系,抽象类中的抽象方法就必须在子类中实现;除非抽象类的子类也是抽象类。在子类中声明抽象方法也是用override关键字;
语法:访问修饰符 override 返回值类型 方法名()
{
//方法体
}
举例
//抽象类和抽象方法
public abstract class Tube
{
public Tube(){} //无参构造函数
//抽象方法
public abstract void Run();
}
//子类
public class Teach:Tube
{
public Teach(){} //无参构造函数
public override void Run()
{
Console.WriteLine("子类实现抽象方法");
}
}
3、抽象方法和虚方法的区别
抽象类、抽象方法和虚方法都可以实现多态,但是还是由区别的;
虚方法 | 抽象方法 |
---|---|
用virtual修饰 | 用abstract修饰 |
要有方法体,哪怕是一个分号 | 不允许有方法体 |
可以被子类override | 必须被子类override |
除了密封类外都可以定义 | 只能在抽象类中定义 |
2、面向对象的三大特性
面向对象的三大特性是:封装、继承、多态
封装:保证对象自身数据的完整性和安全性;
继承:建立类之间的关系,实现代码复用、方便系统的扩展;
多态:相同的方法调用可实现不同的实现方式。
抽象方法,这些方法只有定义,如何实现都是由抽象类的非抽象子类完成。
2、抽象方法和抽象类的应用
1、如何在子类中实现抽象方法
一旦确认继承关系,抽象类中的抽象方法就必须在子类中实现;除非抽象类的子类也是抽象类。在子类中声明抽象方法也是用override关键字;
语法:访问修饰符 override 返回值类型 方法名()
{
//方法体
}
举例
//抽象类和抽象方法
public abstract class Tube
{
public Tube(){} //无参构造函数
//抽象方法
public abstract void Run();
}
//子类
public class Teach:Tube
{
public Teach(){} //无参构造函数
public override void Run()
{
Console.WriteLine("子类实现抽象方法");
}
}
3、抽象方法和虚方法的区别
抽象类、抽象方法和虚方法都可以实现多态,但是还是由区别的;
虚方法 | 抽象方法 |
---|---|
用virtual修饰 | 用abstract修饰 |
要有方法体,哪怕是一个分号 | 不允许有方法体 |
可以被子类override | 必须被子类override |
除了密封类外都可以定义 | 只能在抽象类中定义 |
2、面向对象的三大特性
面向对象的三大特性是:封装、继承、多态
封装:保证对象自身数据的完整性和安全性;
继承:建立类之间的关系,实现代码复用、方便系统的扩展;
多态:相同的方法调用可实现不同的实现方式。