多态
1.装箱和拆箱
- 概念:
装箱:将值类型转换成引用类型的过程
拆箱:将引用类型转换成值类型的过程
例如:使用ArrayList集合时就经常会用到装箱的过程
int n = 10;
object o = n;//这个就是装箱的过程
int nn = (int)o;//这个就是拆箱的过程
- 注意:
判断有没有装箱和拆箱的操作时,要看这两种类型有没有继承关系,有继承关系有可能有装箱和拆箱的操作,没继承关系就不可能有装箱拆箱的操作。
//没有发生拆箱的操作
string str = "123";
int n = Convert.ToInt32(str);//string类型虽说是引用类型,但是两者没有继承关系。
//装箱的操作
int n = 10;
IComparable i = n;//这两个数据类型有继承关系
2.多态
- 概念:
让一个对象能表现出多种状态或者类型。
注意:使用多态时,需要让对象继承。
- 实现多态的方法:
1.虚方法
2.抽象类
3.接口
2.1 虚方法
- 步骤:
1.使用关键字virtual标记父类中的方法,表示这个方法可以被子类重写。
2.使用override关键字标记子类的方法,表示子类可以重写父类的方法。
//类
public class Person
{
string name;
public Person(string name)
{
this.name = name;
}
public virtual void SayHello()
{
Console.WriteLine("我是人类");
}
}
public class Chinese : Person
{
public Chinese(string name) : base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是中国人,我叫{0}", this.Name);
}
}
public class Japanese : Person
{
public Japanese(string name) : base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是日本人,我叫{0}", this.Name);
}
}
public class Korean : Person
{
public Korean(string name) : base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是韩国人,我叫{0}", this.Name);
}
}
public class American : Person
{
public American(string name) : base(name)
{
}
public override void SayHello()
{
Console.WriteLine("我是美国人,我叫{0}", this.Name);
}
}
//主函数
Chinese cn1 = new Chinese("韩梅梅");
Chinese cn2 = new Chinese("李雷");
Japanese j1 = new Japanese("树下君");
Japanese j2 = new Japanese("井边子");
Korean k1 = new Korean("金秀贤");
Korean k2 = new Korean("金贤秀");
American a1 = new American("科比布莱恩特");
American a2 = new American("奥尼尔");
//建立父类数组,子类可以赋值给父类
Person[] pers = { cn1, cn2, j1, j2, k1, k2, a1, a2 };
for (int i = 0; i < pers.Length; i++)
{
// if(pers[i]is Chinese)
// {
// ((Chinese)pers[i]).SayHello();
// }
// else if(pers[i] is Japanese)
// {
// ((Japanese)pers[i]).SayHello();
// }
// else if(pers[i] is Korea)
// {
// ((Korea)pers[i]).SayHello();
// }
// else
// {
// ((American)pers[i]).SayHello();
// }
//如果我们使用多态,就能省略掉这么多代码。
pers[i].SayHello();
}
注意:当使用pers[i].SayHello()的时候,他会根据存在数组的对象类型来寻找所要输出的语句,来代替掉父类的SayHello()方法。
2.2 抽象类
- 概念:
当父类中的方法不知道该怎么实现时,可以考虑将父类写成抽象类。
- 方法:
abstract关键字来标记一个类是抽象类,同样用abstruct关键字来标记一个方法是抽象方法,但是这个抽象方法没有方法体。
注意:
1.抽象成员必须标记为abstract,并且不能有任何实现
2.抽象成员必须在抽象类中
3.抽象类不能被实例化(因为这个类如果实例化,并不能调用到自己的任何成员,没有意义。)
4.子类继承抽象类后,必须把父类中的所有抽象成员都重写(除非子类也是一个抽象类,可以不重写)
5.抽象成员的访问修饰符不能是private(如果是private,子类就不能访问到该方法,也就不能实现)
6.在抽象类中可以包含实例成员,并且抽象类的实例成员可以不被子类实现(虽然自己用不了但是子类都可以继承)
7.抽象类是有构造函数的,虽然不能被实例化。
8.如果父类的抽象方法中有参数,那么继承这个抽象父类的子类在重写父类的方法的时候,必须传入相对应的参数。如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候也必须有返回值。
//类
public abstract class Animal
{
public abstract void Bark();
}
public class Dog : Animal
{
public override void Bark()
{
Console.WriteLine("狗狗汪汪的叫");
}
}
public class Cat : Animal
{
public override void Bark()
{
Console.WriteLine("猫咪喵喵的叫");
}
}
//主函数
Animal a = new Dog();
a.Bark();
Console.ReadKey();
2.3 接口
- 概念:
1.接口是指定一组函数成员,而不实现他们的引用类型。
2.接口使用interface 关键字进行定义,可由方法、属性、事件、索引器或这四种成员类型的任意组合构成。3.接口是一种规则。类似于电脑上的USB插口,如果电脑想使用U盘之类的,必须要遵守U盘的规则,需要在电脑上装上USB插口。
- 接口的特点:
1、接口类似于抽象基类,不能直接实例化接口;接口中的方法都是抽象方法,实现接口的任何非抽象类型都必须实现接口的所有成员:
2、当显式实现该接口的成员时,实现的成员不能通过类实例访问,只能通过接口实例访问。
3、当隐式实现该接口的成员时,实现的成员可以通过类实例访问,也可以通过接口实例访问,但是实现的成员必须是公有的。
4、接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型、不能包含静态成员。
5、接口成员是默认public,且不能包含任何访问修饰符。
6、接口自身可从多个接口继承,类和结构可继承多个接口,但接口不能继承类。
7、当一个类既继承基类,又继承接口的时候,必须基类写在前面,基类和接口用逗号隔开,一个类只能有一个基类,可以继承许多接口。
// 定义一个爬树接口
public interface IClimbTree
{
void ClimbTree();
}
// 定义一个抓老鼠接口
public interface ICatchMice
{
void CatchMice();
}
// 定义一个宠物类
public class Pet
{
public void Eat()
{
Console.WriteLine("吃着真香");
}
}
// 猫猫类,继承于宠物类,又实现了爬树和抓老鼠接口
public class Cat:Pet,IClimbTree,ICatchMice
{
public void ClimbTree()
{
Console.WriteLine("我会爬树");
}
public void CatchMice()
{
Console.WriteLine("我会抓老鼠");
}
}
class Program
{
static void Main(string[] args)
{
//实例化一个猫咪对象
Cat cat = new Cat();
cat.Eat();
cat.ClimbTree();
cat.CatchMice();
Console.ReadLine();
}
}
- 显示接口:
如果继承接口的类中的方法与接口的方法重名时,此时可以显示接口。
public interface IFlyable
{
void Fly();
}
public void Bird:IFlyable
{
public void Fly()
{
Console.WriteLine("鸟会飞");
}
//显示接口的方法
void IFlyable.Fly()
{
Console.WriteLine("我是接口的飞");
}
}
//主函数
IFlyable fly = new Bird();
fly.Fly();//这是接口的飞
Bird bird = new Bird();
bird.fly();//这是自己的飞
3.部分类
当多个人共同完成一个项目时,这些人对同一个类都有补充的,但是普通的类不像是方法,是不能命名相同的名字 ,所以需要关键字partial来将这个类变成部分类。
public partial void Person
{
private string _name;
}
public partail void Person
{
private int age;
}
//这两个类里里面的字段和方法是可以共用的。
4.密封类
当想让一个类不继承别的类时,就可以使用关键字sealed来使这个类变成密封类。虽说不能继承别的类,但是别的类可以继承它。
public sealed void Person
{
}
5.重写父类的ToString()的方法
C#的每一个类和结构都隐式继承自System.Object,而Object提供了ToString()虚方法,所以任何类的对象都有ToString()方法,该方法可以将对象转化为字符串类型(也可理解为:将数值或其它类型对象转换为字符串类型),该方法为虚方法,可以重写。
- 当不重写时:
namespace Test
{
public class Person
{
}
}
//Main函数
Person p= new Person ;
Console.WriteLine(p.ToString());//输出的是这个对象所在的命名空间。
- 当对父类重写时:
namespace Test
{
public class Person
{
public override string ToString()
{
return "Hello World";
}
}
}
//Main函数
Person p= new Person ;
Console.WriteLine(p.ToString());//输出Hello World