17.3 泛型类型的声明和实例化

我们已经看过了泛型类型的示例代码,可以看出泛型类型的声明和普通类型很相似,但泛型类型的声明也要满足如下规则:

❑在类名称后跟一对尖括号,括号中为若干个类型参数,多个类型参数之间使用逗号进行分隔,类型参数实际上是类型占位符。

❑在类声明的主体中使用类型参数来表示应该被替代的类型,一般是方法的参数类型、返回类型,或者作为字段、属性的类型等。

例如,我们声明这样一个泛型类:MyClass<T1,T2>,其中的T1和T2是类型参数,其源代码如代码清单17-4所示。

特别注意参数T1和T2在类中所处的位置,一般都是作为方法的参数类型、返回类型,或者作为字段、属性的类型等。

接下来,我们要学习的是如何实例化泛型类型,或者换句话说,如何使用泛型类型。因为泛型类型使用了类型占位符——类型参数,那么在实例化泛型类型之前,要给这些类型参数赋予真实的类型,以此让编译器知道该使用什么类型来替换这些类型参数,从而创建一个具有具体类型的对象。

和声明一个泛型类型相似,只需将真实类型放入尖括号中的对应位置即可,编译器就会明白每个类型参数所代表的具体类型,在运行时这些类型参数就会被相应的具体类型所替换。正如方法的参数有形参和实参一样,类型参数也有形参和实参。<T>中的T就是形参,而<int>中的int就是类型实参。

代码清单17-4 泛型类MyClass<T1,T2>的源代码

17.3 泛型类型的声明和实例化 - 图1

编译器使用类型实参以替换泛型类型中定义的类型参数以后,就会创建一个构造类型,此构造类型用以创建具体类型的实例。

对于代码清单17-4的例子,分别使用int和string类型进行初始化,如图17-3所示。

17.3 泛型类型的声明和实例化 - 图2

图 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.3 泛型类型的声明和实例化 - 图3

图 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