17.3 泛型类型的声明和实例化
我们已经看过了泛型类型的示例代码,可以看出泛型类型的声明和普通类型很相似,但泛型类型的声明也要满足如下规则:
❑在类名称后跟一对尖括号,括号中为若干个类型参数,多个类型参数之间使用逗号进行分隔,类型参数实际上是类型占位符。
❑在类声明的主体中使用类型参数来表示应该被替代的类型,一般是方法的参数类型、返回类型,或者作为字段、属性的类型等。
例如,我们声明这样一个泛型类:MyClass<T1,T2>,其中的T1和T2是类型参数,其源代码如代码清单17-4所示。
特别注意参数T1和T2在类中所处的位置,一般都是作为方法的参数类型、返回类型,或者作为字段、属性的类型等。
接下来,我们要学习的是如何实例化泛型类型,或者换句话说,如何使用泛型类型。因为泛型类型使用了类型占位符——类型参数,那么在实例化泛型类型之前,要给这些类型参数赋予真实的类型,以此让编译器知道该使用什么类型来替换这些类型参数,从而创建一个具有具体类型的对象。
和声明一个泛型类型相似,只需将真实类型放入尖括号中的对应位置即可,编译器就会明白每个类型参数所代表的具体类型,在运行时这些类型参数就会被相应的具体类型所替换。正如方法的参数有形参和实参一样,类型参数也有形参和实参。<T>中的T就是形参,而<int>中的int就是类型实参。
代码清单17-4 泛型类MyClass<T1,T2>的源代码
编译器使用类型实参以替换泛型类型中定义的类型参数以后,就会创建一个构造类型,此构造类型用以创建具体类型的实例。
对于代码清单17-4的例子,分别使用int和string类型进行初始化,如图17-3所示。
图 17-3 泛型类型的实例化
上述例子演示的是使用int、string这两个类型实参来实例化泛型类,也可以使用其他类型来实例化这个泛型类,例如,分别为两个类型参数T1、T2指定int和string类型,或者指定long和short类型。可见,使用泛型非常的灵活,可以根据自己的需要来构造满足要求的类型,这其中的每一个都是独立的类型,互相不影响,这就是泛型的魅力,它重用了代码逻辑,将类型抽象了出来,如图17-4所示。
MyClass<int,string>myClass=new MyClass<int,string>();
MyClass<long,short>myClass2=new MyClass<long,short>();
图 17-4 从泛型类型创建的两个实例
接下来,我们给出代码清单17-1所示的“栈”的完整代码,如代码清单17-5所示。
代码清单17-5 使用泛型改写的栈之完整示例
1 namespace ProgrammingCSharp4 2{
3
class GenericsSample
4{
5 public static void Main()
6{
7 Stack<int>intStack=new Stack<int>(5);
8 System.Console.WriteLine("Push:10");
9 intStack.Push(10);
10 System.Console.WriteLine("Push:9");
11 intStack.Push(9);
12 System.Console.WriteLine("Pop:{0}",intStack.Pop());
13 System.Console.WriteLine("Pop:{0}",intStack.Pop());
14
15 Stack<string>stringStack=new Stack<string>(5);
16 System.Console.WriteLine("Push:'hello'");
17 stringStack.Push("hello");
18 System.Console.WriteLine("Push:'world'");
19 stringStack.Push("world");
20 System.Console.WriteLine("Pop:{0}",stringStack.Pop());
21 System.Console.WriteLine("Pop:{0}",stringStack.Pop());
22}
23}
24
25 class Stack<T>
26{
27 private int_size;
28 private int_pointer;
29 private T[]_db;
30
31 public Stack(int size)
32{
33_size=size;
34_db=new T[_size];
35}
36
37 public void Push(T data)
38{
39 int tmp=_pointer++;
40 if(tmp<_size)
41{
42_db[tmp]=data;
43}
44}
45
46 public T Pop()
47{
48 return_db[—_pointer];
49}
50}
51}
上述代码的运行结果为:
Push:10
Push:9
Pop:9
Pop:10
Push:'hello'
Push:'world'
Pop:world
Pop:hello