1. 构造器
知识点一:构造器从来都没有返回值,其中不能包含return语句(一般的成员方法要在方法名称前面加上void关键字,而构造器不用)
知识点二:类中的成员变量如果不对其进行初始化(即赋值),如果为int型的成员变量,则默认初始化为0,string在默认初始化为NULL
知识点三:类中的成员变量不赋值即可使用,而局部变量必须赋初值后才可使用
知识点四:this关键字,this是C#中隐含的指针,当类实例化时把对象的地址赋值给this
知识点五:实际开发中带参数的构造器中的参数名称最好和成员变量名称不同,如果相同必须加上this关键字加以区别,this.i代表成员变量,i代表是构造器中的参数
知识点六:如果在声明成员变量时给成员变量赋了初值,且构造器的重载个数较多,会产生大量的代码冗余(可以通过MIL查看,有大量重复代码)消除冗余的方法:将成员变量在无参构造器中进行初始化,然后用有参构造器调用无参构造器,调用无参构造器的方法:在有参构造器的后面加上:this(),再通过MIL查看中间代码,冗余消失了。
实例代码:
using System;
namespace ConsoleApplication1
{
class A
{
public int i;//声明两个成员变量
public string s;
public A()//无参构造器,并对成员变量进行初始化
{
i = 100;
s = "我的梦想是一名程序员";
}
public A(int _i):this()//有参数的构造器,并调用无参构造器
{
i = _i;
}
public A(string _s):this()
{
s=_s;
}
}
class Test
{
static void Main(string[] args)
{
A a = new A(200);
Console.WriteLine(a.i);
A a1=new A("程序呀");
Console.WriteLine(a1.s);
}
}
}
知识点七:在类的继承中,派生类在实例化时,先执行父类的无参构造器,才执行自己的构造器
知识点八:只有基类的无参构造器会被继承,有参构造器不被继承
知识点九:建立类时会自动生成一个无参数的构造器,但如果定义了有参数的构造器,就不生成无参数的构造器了
知识点十:引用父类的构造器的方法::base(参数)
知识点十一:在一个程序执行的过程中,静态构造器最多执行一次;静态构造器在类的静态成员初始化后执行(或者讲编译器会将静态成员初始化语句转换成赋值语句放在静态构造器执行的最开始);静态构造器在任何类的静态成员被引用之前执行;静态构造器在任何类的实例变量被分配之前执行。
2. 类的修饰符
访问修饰符 | 类内部 | 子类 | 程序集内 | 程序集外 |
default | 可以 |
|
|
|
public | 可以 | 可以 | 可以 | 可以 |
private | 可以 |
|
|
|
internal | 可以 | 可以 | 可以 |
|
protected | 可以 | 可以 |
|
|
Protected internal | 可以 | 可以 | 可以 |
|
注意:关键字class前面如果没有修饰符默认为internal,类的成员前面如果没有修饰符默认为private
Sealed访问修饰符说明此类不能被继承
3. 虚方法
使用虚方法的实例:
using System;
namespace ConsoleApplication1
{
class Employee
{
protected string _name;
public Employee()
{
}
public Employee(string name)
{
_name = name;
}
public virtual void StartWork() //虚方法
{
Console.Write(_name+"开始工作:");
}
}
class Manager : Employee
{
public Manager(string name) : base(name) { }//继承父类的带参数的构造方法
public override void StartWork() //虚方法重写
{
base.StartWork();
Console.WriteLine("给员工下达任务");
}
}
class Seller : Employee
{
public Seller(string name) : base(name) { }
public override void StartWork()
{
base.StartWork();
Console.WriteLine("销售产品");
}
}
class Test
{
static void Main(string[] args)
{
Employee[] emp = new Employee[4];//employee类的对象数组,存储的是地址值
emp[0] = new Manager("张三");
emp[1] = new Seller("李四");
emp[2] = new Manager("王五");
emp[3] = new Seller("赵六");
Console.WriteLine("早上8点开始工作:");
foreach (Employee e in emp)
{
e.StartWork();
}
}
}
}
4. 抽象类
知识点一:抽象类不能被实例化
知识点二:抽象类可以包含抽象方法和抽象访问器
知识点三:抽象方法本质上就是一个虚方法,用以实现多态
知识点四:不能用sealed修饰符修改抽象类,派生类必须全部实现抽象类定义的抽象方法和抽象访问器
抽象方法:
1. 抽象方法是隐式的虚方法
2. 只允许在抽象类中使用抽象方法声明
3. 因为抽象方法声明不提供实际的实现,所以没有方法体:方法声明只是以一个分好结束,并且在签名后没有大括号({}),实现由一个重写方法提供,此重写方法是非抽象类的成员
4. 在抽象方法声明中使用static或virtual修饰符是错误的
5. 除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样
6. 在静态属性上使用abstract修饰符是错误的
7. 在派生类中,通过包括使用override修饰符的属性声明,可以重写抽象的继承属性
抽象类的构造函数:
任何情况下,抽象类都不应进行实例化,因此,正确定义其构造函数就非常重要。确保抽象类功能的正确性和扩展性也很重要。下列准则有助于确保抽象类能够正确的设计并在实现后可以按预期的方式工作。
1. 不要在抽象类中定义公共的或受保护的构造函数,具有public或protected internal可见性的构造函数用于能进行实例化的类型。任何情况下抽象类型不能实例化。
2. 应在抽象类中定义一个受保护(protected)构造函数或内部(private)构造函数
3. 如果在抽象类中定义一个受保护构造函数,则在创建派生类的实例时,基类可以执行初始化任务
抽象方法和虚方法的区别:
1. 抽象方法和虚方法的区别在于:虚方法有一个实现部分,并为派生类提供了覆盖该方法的选项,相反,抽象方法没有提供实现部分,强制派生类覆盖方法(否则派生类不能称为具体类)
2. abstract方法只能在抽象类中声明,虚方法则不是
3. abstract方法必须在派生类中重写,而virtual则不必
4. abstract方法不能声明方法体,虚方法则可以
抽象类的例子:
using System;
namespace ConsoleApplication1
{
abstract class Employee
{
protected string _name;
protected Employee()
{
}
protected Employee(string name)
{
_name = name;
}
public abstract void StartWork(); //虚方法
}
class Manager : Employee
{
public Manager(string name) : base(name) { }//继承父类的带参数的构造方法
public override void StartWork() //虚方法重写
{
Console.WriteLine(_name+"开始工作:"+"给员工下达任务");
}
}
class Seller : Employee
{
public Seller(string name) : base(name) { }
public override void StartWork()
{
Console.WriteLine(_name+"开始工作:"+"销售产品");
}
}
class Test
{
static void Main(string[] args)
{
Employee[] emp = new Employee[4];//employee类的对象数组,存储的是地址值
emp[0] = new Manager("张三");
emp[1] = new Seller("李四");
emp[2] = new Manager("王五");
emp[3] = new Seller("赵六");
Console.WriteLine("早上8点开始工作:");
foreach (Employee e in emp)
{
e.StartWork();
}
}
}
}
从以上代码可以看到存在大量重复的代码,因此此实例不适合用抽象类实现,这里知识为了演示抽象类的用法