1、新建一个person类
public class Person { public string Name; public Person(string name) { this.Name = name; } public void SayHello() { Console.WriteLine($@"我是人,是叫{Name}"); } }
2、新建几个person的子类
public class Chinese : Person { public Chinese(string name) : base(name) { } public void SayHello() { Console.WriteLine("我是中国人,我叫{0}", this.Name); } } public class Japanese : Person { public Japanese(string name) : base(name) { } public void SayHello() { Console.WriteLine("我是日本人,我叫{0}", this.Name); } } public class Korea : Person { public Korea(string name) : base(name) { } public void SayHello() { Console.WriteLine("我是韩国人,我叫{0}", this.Name); } } public class American : Person { public American(string name) : base(name) { } public void SayHello() { Console.WriteLine("我是美国人,我叫{0}", this.Name); } }
3、这时候,创建几个不同的对象,把内容给展示出来
static void Main(string[] args) { //多态:让一个对象能够表现出多种的状态(类型) Chinese cn1 = new Chinese( "李雷"); Chinese cn2 = new Chinese("韩梅梅"); Japanese j1 = new Japanese("松下幸之助"); Korea k1 = new Korea("金秀贤"); American a1 = new American("科比"); American a2 = new American("奥尼尔"); List<Person> list = new List<Person>() {cn1,cn2,j1,k1,a1,a2 }; foreach (Person p in list) { p.SayHello(); } Console.ReadKey(); }
4、那么问题来了,这里每个对象调用的都是父类的方法,没有调用自己类的方法,如果我希望调用的是自己的方法,那该怎么办呢?
foreach (Person p in list) { if (p is Chinese) { Chinese cn = (Chinese)p; cn.SayHello(); } else if(p is Korea) { Korea ko = (Korea)p; ko.SayHello(); } else if (p is Japanese) { Japanese jp = (Japanese)p; jp.SayHello(); } else if (p is American) { American am = (American)p; am.SayHello(); } } Console.ReadKey();
5、这里使用了if else 进行类型判断后转换的方法。除此之外还有没有别的方法呢?有三种方法:A、虚方法 B、抽象类 C、接口
A、将父类的方法标记为虚方法,使用virtual,在子类的方法前面加override
public class Person { public string Name; public Person(string name) { this.Name = name; } public virtual void SayHello() { Console.WriteLine($@"我是人,是叫{Name}"); } } 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 Korea : Person { public Korea(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); } }
说明:调用了父类的sayHello,然而这个list中装的是子类的对象,于是就用子类的方法。如果这时存入的是Person的对象,依然会使用Person的方法。
B、用抽象类实现。抽象类中,写抽象方法。抽象方法是没有方法体的(即,没有大括号)。这个方法是没法运行的,他的存在意义就是让子类来实现它。
class Program { static void Main(string[] args) { Chinese cn1 = new Chinese( "李雷"); Chinese cn2 = new Chinese("韩梅梅"); Japanese j1 = new Japanese("松下幸之助"); Korea k1 = new Korea("金秀贤"); American a1 = new American("科比"); American a2 = new American("奥尼尔"); //Person p1 = new Person("Aman"); List<Person> list = new List<Person>() { cn1, cn2, j1, k1, a1, a2 };// ,p1}; foreach (Person p in list) { p.SayHello(); } Console.ReadKey(); } } public abstract class Person { public string Name; public Person(string name) { this.Name = name; } public abstract void SayHello();//抽象方法
//{} }
注意这里的区别,如果是A虚方法,那么他自己也是可以运行的,如果是抽象的,就没法创建对象了。(接口也不能创建对象)
C、接口。
接口是一种规范,也是一种能力。以 I 开头 ,以able结尾 如 IFlyable。
接口中不需要访问修饰符,都是public的。
接口中不能写具有方法体的函数,光说不做,只是定义了一组未实现的成员。
接口中不能有字段。(但是可以有 string Name {get;set;} 这样的自动属性。其实这也是方法)
接口和接口之间可以结成,并且可以多继承。
接口并不能用去继承一个类。实现接口的类,必须实现所有的接口。
interface ISayHelloable { string Name { get; set; } void SayHello(); } public class Chinese: ISayHelloable { public Chinese(string inputName) { Name = inputName; } string chineseName; public string Name { get{return chineseName ; } set{ chineseName = value;} } public void SayHello() { Console.WriteLine($@"我是中国人,我的中国名字叫{Name}"); } } public class American : ISayHelloable { public American(string inputName) { Name = inputName; } string AmericanName; public string Name { get { return AmericanName; } set { AmericanName = value; } } public void SayHello() { Console.WriteLine($@"我是美国人,我的美国名字叫{Name}"); } }
首先定义一个接口,并用两个类去实现这个接口。
再创建两个不同的类对象,因为他们都实现了这个接口,于是定义一个List把他们装进来。
然后用接口的方法来分别调用各自的方法。
static void Main(string[] args) { List<ISayHelloable> persons = new List<ISayHelloable>(); persons.Add(new Chinese("李磊")); persons.Add(new American("Adam")); persons.Add(new Chinese("韩梅梅")); persons.Add(new American("John")); foreach (ISayHelloable p in persons) { p.SayHello(); } Console.ReadKey(); }
综上:
1、构建“主从”这种关系的类时,使用虚方法。
2、构建“父子”这种关系的类时,使用抽象。
3、在哪里都可以用接口。
接口的优势:A、多继承。B、相互之间无关的类实现你的接口。C、想指定一个特定数据类型的行为,但是不用去关心由谁来实现这一行为。
说的不全面,暂且这么记,以后对这个问题认识深刻后,再来修改。