继承
密封类
密封类(关键字sealed)是不允许其它类继承的,类似Java中的final关键字。
1 public sealed class SealedClassName 2 { 3 //... 4 }
初始化顺序
子类初始化顺序如下:
- 初始化类的实例字段;
- 调用基类的构造函数;
- 调用子类的构造函数。
1 using System; 2 3 namespace Study 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 new C(); 10 11 Console.ReadKey(); 12 } 13 } 14 15 public class A 16 { 17 public A() 18 { 19 Console.WriteLine("A 类构造函数被调用。"); 20 } 21 } 22 23 public class B : A 24 { 25 public B() 26 { 27 Console.WriteLine("B 类构造函数被调用。"); 28 } 29 } 30 31 public class C : B 32 { 33 public C() 34 { 35 Console.WriteLine("C 类构造函数被调用。"); 36 } 37 } 38 }
结果如下:
1 A 类构造函数被调用。 2 B 类构造函数被调用。 3 C 类构造函数被调用。
带参数的构造函数
Java中使用super调用父类的构造函数,而C#中则使用base,同时写法也稍微有点不同,如下:
1 using System; 2 3 namespace Study 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 new C(); 10 11 Console.ReadKey(); 12 } 13 } 14 15 public class A 16 { 17 public A(int a, int b) 18 { 19 Console.WriteLine("A 类构造函数被调用。"); 20 Console.WriteLine(a + ":" + b); 21 } 22 } 23 24 public class B : A 25 { 26 public B(int name1, int name2) : base(name1, name2) 27 { 28 Console.WriteLine("B 类构造函数被调用。"); 29 } 30 } 31 32 public class C : B 33 { 34 public C() : base(50, 100) 35 { 36 Console.WriteLine("C 类构造函数被调用。"); 37 } 38 } 39 }
输出如下:
1 A 类构造函数被调用。 2 50:100 3 B 类构造函数被调用。 4 C 类构造函数被调用。
方法多态
子类重写父类的方法使用virtual和override实现。
1 using System;
2
3 namespace Study
4 {
5 class Program
6 {
7 static void Main(string[] args)
8 {
9 new C().func();
10
11 Console.ReadKey();
12 }
13 }
14
15 public class A
16 {
17 public virtual void func()
18 {
19 Console.WriteLine("A 类的 func 方法调用。");
20 }
21 }
22
23 public class B : A
24 {
25 public override void func()
26 {
27 Console.WriteLine("B 类的 func 方法调用。");
28 }
29 }
30
31 public class C : B
32 {
33 public override void func()
34 {
35 base.func();
36 Console.WriteLine("C 类的 func 方法调用。");
37 }
38 }
39 }
输出如下:
1 B 类的 func 方法调用。 2 C 类的 func 方法调用。
阻止重写方法
如果不希望虚方法被重写,可以使用sealed关键字。
1 public sealed override void func()
2 {
3 //...
4 }
新成员方法隐藏老成员方法
使用new关键字可以隐藏非虚的老成员方法。
1 using System;
2
3 namespace Study
4 {
5 class Program
6 {
7 static void Main(string[] args)
8 {
9 C c = new C();
10 c.func();
11 ((B)c).func();
12 ((A)c).func();
13
14 Console.ReadKey();
15 }
16 }
17
18 public class A
19 {
20 public void func()
21 {
22 Console.WriteLine("A 类的 func 方法调用。");
23 }
24 }
25
26 public class B : A
27 {
28 public new void func()
29 {
30 Console.WriteLine("B 类的 func 方法调用。");
31 }
32 }
33
34 public class C : B
35 {
36 public new void func()
37 {
38 Console.WriteLine("C 类的 func 方法调用。");
39 }
40 }
41 }
输出如下:
1 C 类的 func 方法调用。 2 B 类的 func 方法调用。 3 A 类的 func 方法调用。
接口
C#中不允许多重继承,但接口可以多重继承。
接口声明
声明一个接口的写法如下:
1 public interface ICustom 2 { 3 }
C#中接口规则:
- 定义的方法不需要添加public等限定符,默认的所有方法都是public的;
- 可以包含方法、属性、事件和索引器;
- 不可以包含字段、运算符重载、构造函数和析构函数;
- 也不可以包含静态相关的所有定义;
类实现接口
实现接口的写法与继承一致:
1 using System; 2 3 namespace Study 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 ICustom custom = new Custom(); 10 custom.name = "A"; 11 custom.MoveTo(200, 100); 12 13 Console.ReadKey(); 14 } 15 } 16 17 public interface ICustom 18 { 19 string name { set; get; } 20 21 void MoveTo(float x, float y); 22 } 23 24 public class Custom : ICustom 25 { 26 public string name { get; set; } 27 28 public void MoveTo(float x, float y) 29 { 30 Console.WriteLine("Custom "" + name + "" move to: " + x + ", " + y); 31 } 32 } 33 }
输出如下:
Custom "A" move to: 200, 100
接口的隐式实现和显式实现
如果在实现接口时没有指明该方法是属于哪个接口的话,称为隐式实现,如上面的例子。如果指明了方法是来自哪个接口则称为显式实现。
C#中的隐式实现与Java和AS3的使用一致,就不多讲,下面主要说一下接口的显式实现。
1 using System; 2 3 namespace Study 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 Custom custom = new Custom(); 10 custom.name = "A"; 11 (custom as ICustomA).MoveTo(200, 100); 12 (custom as ICustomB).MoveTo(200, 100); 13 14 Console.ReadKey(); 15 } 16 } 17 18 public interface ICustomA 19 { 20 string name { set; get; } 21 22 void MoveTo(float x, float y); 23 } 24 25 public interface ICustomB 26 { 27 string name { set; get; } 28 29 void MoveTo(float x, float y); 30 } 31 32 public class Custom : ICustomA, ICustomB 33 { 34 public string name { get; set; } 35 36 void ICustomA.MoveTo(float x, float y) 37 { 38 Console.WriteLine("ICustomA "" + name + "" move to: " + x + ", " + y); 39 } 40 41 void ICustomB.MoveTo(float x, float y) 42 { 43 Console.WriteLine("ICustomB "" + name + "" move to: " + x + ", " + y); 44 } 45 } 46 }
运行结果如下:
1 ICustomA "A" move to: 200, 100 2 ICustomB "A" move to: 200, 100
显示接口总结:
- 显示接口一般用于多个接口实现时,存在同名方法但需要不同的处理时。
- 我们发现如果使用显示的接口,需要将对象转换为对应的接口对象才能调用到对应的接口方法。
- 显示实现接口时不能写public在前方。
- 显示实现的接口不能由类直接访问,必须转换为对应的接口对象才行。
抽象类
C#中,抽象类使用与Java中一致,我们写一个例子来验证即可。
1 using System; 2 3 namespace Study 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 Custom custom = new Custom(); 10 custom.name = "A"; 11 custom.MoveTo(200, 100); 12 13 Console.ReadKey(); 14 } 15 } 16 17 public abstract class AbstractCustom 18 { 19 public string name { set; get; } 20 21 public abstract void MoveTo(float x, float y); 22 } 23 24 public class Custom : AbstractCustom 25 { 26 public override void MoveTo(float x, float y) 27 { 28 Console.WriteLine("Custom "" + name + "" move to: " + x + ", " + y); 29 } 30 } 31 }
运行结果如下:
Custom "A" move to: 200, 100
抽象类总结:
- 抽象类也是类,所以不能多重继承;
- 抽象类不能实例化,可以包含抽象方法,抽象方法不能实现;
- 抽象方法为虚方法;
- 非抽象子类必须实现抽象方法;