一、基本定义
构造函数
构造函数是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 。
特别的,一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们。即构造函数的重载。
重载(Overloading)
方法重载是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,及参数的数量或参数的类型不能完全相同。
理解概念:
重载:当年,大街上看到冰淇淋店有一款草莓冰淇淋,对它产生了深深地爱意。事过多年,在同一个地点,遇上了同一款冰淇淋,但此时,再也产生不了当年的爱意。同样的大街(类),同样的冰淇淋(方法),因为条件改变(参数类型),就再也产生不了爱意(返回结果),这时候,我的感情就被重载了(或许是厌恶,或许是无所谓)。
重写(Overriding)
方法重写是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型。
注意:
1. 子类中不能重写父类中的final方法
2. 子类中必须重写父类中abstract方法
\
二、实现方法
重写(Overriding):
通常,派生类继承基类的方法。因此,在调用对象继承方法的时候,调用和执行的是基类的实现。但是,有时需要对派生类中的继承方法有不同的实现。
例如,假设动物类存在“跑”的方法,从中派生出马和狗,马和狗的跑得形态是各不相同的,因此同样方法需要两种不同的实现,这就需要”重新编写”基类中的方法。”重写”基类方法就是修改它的实现或者说在派生类中重新编写。
重载(Overloading):
在一个类中用相同的名称但是不同的参数类型创建一个以上的过程、实例构造函数或属性。
三、详细理解
| 范围 | 方法名 | 参数列表 | 修饰符 | 抛出父类没有的异常 | 返回类型 | 与面向对象 | |
|---|---|---|---|---|---|---|---|
| 重载 | 同一个类 | 相同 | 不同 | 无关 | 可以 | 不同 | 多态 |
| 重写 | 不同的类 | 相同 | 相同 | 大于父类方法 | 不可以 | 相同 | 继承 |
重写(Overriding)(又称覆盖)
- 父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。但有时子类并不想原封不动地继承父类的方法,而是想做一定修改,这就需要采用方法重写(Overriding)。
- 若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
- 子类函数的访问修饰权限不能少于父类的。
为什么要重写父类的方法
通常,子类继承父类的方法,在调用对象继承方法的时候,调用和执行的是父类的实现。但是,有时候需要
对子类中的继承方法有不同的实现方式。例如,假设动物存在“跑”的方法,从中继承有狗类和马类两个子类
如何重写
A.重写父类的方法要用到override关键字(具有override关键字修饰的方法是对父类中同名方法的新实现)
B.要重写父类的方法,前提是父类中该要被重写的方法必须声明为virtual或者是abstract类型。给父类中
要被重写的方法添加virtual关键字表示可以在子类中重写它的实现。(注意:C#中的方法默认并不是
virtual类型的,因此要添加virtual关键字才能够被重写)
C.virtual关键字用于将方法定义为支持多态,有virtual关键字修饰的方法称为“虚拟方法”
[访问修饰符] virtual [返回类型] 方法名(参数列表)
{
//虚拟方法的实现,该方法可以被子类重写
}
重写举例:
namespace inheritDemo2
{
class Employee
{
public virtual void EmpInfo()
{
Console.WriteLine("用virtual关键字修饰的方法是虚拟方法");
}
}
class DervEmployee : Employee
{
public override void EmpInfo()
{
base.EmpInfo();//base关键字将在下面拓展中提到
Console.WriteLine("该方法重写base方法");
}
}
class Test
{
static void Main(string[] args)
{
DervEmployee objDervEmployee = new DervEmployee();
objDervEmployee.EmpInfo();
//注意:objDervEmployee派生类的实例是赋给Employee类的objEmployee的引用,
// 所以objEmployee引用调用EmpInfo()方法时 还是调用DervEmployee类的方法
Employee objEmployee = objDervEmployee;
objEmployee.EmpInfo();
}
}
}
拓展 :base关键字用于从子类中访问父类成员。即使父类的方法在子类中重写,仍可以使用base关键字调用。
而且,在创建子类实例时,可以使用base关键字调用父类的构造函数。使用base关键字只能访问父类的构造函数、实例方法或实例属性,而不能访问基类的静态方法。
\
重载(Overloading)
- 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数、类型。重载是一个类中多态性的一种表现。
- 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不同。无法以返回类别作为重载函数的区分标准。
四、总结规则
(一)重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。
3、重写的方法的返回值必须和被重写的方法的返回一致或者兼容;
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写;
6、静态方法不能被重写为非静态的方法(会编译出错);
7、父类方法被final时,无论该方法被public、protected及默认所修饰,子类均不能重写该方法。
(二)重载的规则:
1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响。
五、文末有彩蛋
面试题:重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
答:方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。