泛型编程

泛型程序设计（英文：generic programming）是程序设计语言的一种风格或范型。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型，在实例化时作为参数指明这些类型。各种程序语言和其编译器、运行环境对泛型的支持均不同。Ada、Delphi、Eiffel、Java、C#、F#、Swift 和 Visual Basic .NET 称之为泛型（generics）；ML、Scala 和 Haskell 称之为参数多态（parametric polymorphism）；C++ 和 D称之为模板。具有广泛影响的1994年版的《Design Patterns》一书称之为参数化类型（parameterized type）。
泛型的定义及目的.
泛型的定义主要有以下两种：
不论使用哪个定义，泛型的参数在真正使用泛型时都必须作出指明。
一些强类型程序语言支持泛型，其主要目的是加强类型安全及减少-{zh-hans:类; zh-hant:类别;}-转换的次数，但一些支持泛型的程序语言只能达到部份目的。
伪代码例子.
类　例泛类&lt;T&gt; {
　　值 : T
　　设置值(新值 : T) {
　　　　值 := 新值
　　获取值() : T {
　　　　返回　值
例方法1() {
　　例物件 : 例泛类&lt;整数型&gt;
　　例物件 := 新　例泛类&lt;整数型&gt;()
　　例物件.设置值(5)
　　输出整数(例物件.获取值())
例方法2() {
　　例物件 : 例泛类&lt;浮点数型&gt;
　　例物件 := 新　例泛类&lt;浮点数型&gt;()
　　例物件.设置值(5.5)
　　输出浮点数(例物件.获取值())
在这例子中，codice_1是一个泛型，而codice_2是一个类型参数。在codice_1中没指明codice_2的实际类型，只有codice_5和codice_6在使用codice_1时才加以指明。
运行这例子的codice_5将输出整数5，而运行codice_6将输出浮点数5.5。
一些程序语言的泛型特性.
.NET 的泛型.
.NET 泛型的参数只可以代表-{zh-hans:类; zh-hant:类别;}-，不能代表个别-{zh-hans:对象; zh-hant:物件;}-。由于 .NET 泛型的类型参数之实际类型在运行时均不会被消除，运行速度会因为类型转换的次数减少而加快。另外，使用codice_10方法可于程序运行时得知泛型及其类型参数的实际类型，更可以运用反射式编程。
using System;
// 定义一个泛型列表类，T 表示类型参数
public class GenericList&lt;T&gt;
 private T[] _items; // 存储列表items的数组
 private int _count; // 列表中items的计数
 // 构造函数，初始化列表的容量
 public GenericList(int capacity)
 _items = new T[capacity];
 _count = 0;
 // 添加item到列表中
 public void Add(T item)
 if (_count &lt; _items.Length)
 _items[_count] = item;
 _count++;
 else
 Console.WriteLine("List capacity reached."); // 列表容量已满
 // 根据索引获取列表中的item
 public T GetItem(int index)
 if (index &gt;= 0 &amp;&amp; index &lt; _count)
 return _items[index];
 else
 throw new IndexOutOfRangeException("Index out of range."); // 索引超出范围
public class Program
 public static void Main()
 // 创建一个存储整数的泛型列表
 GenericList&lt;int&gt; intList = new GenericList&lt;int&gt;(3);
 intList.Add(1);
 intList.Add(2);
 intList.Add(3);
 Console.WriteLine(intList.GetItem(1)); // 输出: 2
 // 创建一个存储字符串的泛型列表
 GenericList&lt;string&gt; stringList = new GenericList&lt;string&gt;(2);
 stringList.Add("Hello");
 stringList.Add("World");
 Console.WriteLine(stringList.GetItem(0)); // 输出: Hello
在上面的例子中展示了一个简单的泛型列表类 codice_11，它可以存储任何类型的数据（由 codice_2 指定）。codice_13 类中的 codice_14 方法演示了如何使用这个泛型类来存储和检索整数和字符串。
.NET 允许对个别泛型的类型参数进行约束，包括以下几种形式（假设codice_2是泛型的类型参数，codice_16是一般-{zh-hans:类; zh-hant:类别;}-、泛类，或是泛型的类型参数）：
Java 的泛型.
Java 泛型的参数只可以代表-{zh-hans:类; zh-hant:类别;}-，不能代表个别-{zh-hans:对象; zh-hant:物件;}-。由于Java泛型的类型参数之实际类型在编译时会被消除，所以无法在运行时得知其类型参数的类型，而且无法直接使用基本值类型作为泛型类型参数。Java编译程序在编译泛型时会自动加入类型转换的编码，故运行速度不会因为使用泛型而加快。
由于运行时会消除泛型的对象实例类型信息等缺陷经常被人诟病，Java及JVM的开发方面也尝试解决这个问题，例如：Java通过在生成字节码时添加类型推导辅助信息，从而可以通过反射接口获得部分泛型信息；通过改进泛型在JVM的实现，使其支持基本值类型泛型和直接获得泛型信息等。
Java允许对个别泛型的类型参数进行约束，包括以下两种形式（假设codice_2是泛型的类型参数，codice_16是一般-{zh-hans:类; zh-hant:类别;}-、泛类，或是泛型的类型参数）：
C++的泛型（模板）.
C++ 泛型的参数可以代表-{zh-hans:类; zh-hant:类别;}-或个别-{zh-hans:对象; zh-hant:物件;}-。在一般意义上，C++ 缺乏对泛型的类型参数进行直接约束的手段，但可利用 SFINAE（模板代换失败非错误，指在模板实例化过程中的错误仅意味此次代换失败，并不一定产生编译错误）规则及 C++11 的 static_assert 等实现相似功能。
class B{
};
class D: public B{
};
template&lt;typename T&gt;
void SFINAE(const std::enable_if_t&lt;std::is_base_of&lt;B, T&gt;::value, T&gt; &amp;t);
template&lt;typename T&gt;
void STATIC_ASSERT(const T &amp;t){
 static_assert(std::is_pod&lt;T&gt;::value, "Use with POD types only!");
如上所示，std::enable_if（std::enable_if_t&lt;boolean, Type&gt; 是 std::enable_if&lt;boolean, Type&gt;::type 的缩写）利用 SFINAE 规则来实现模板类型参数约束的手段之一。其实现方式是若布尔判断为假，则把类型设为 void，而这将导致 const void &amp; 这种不合法的类型出现，从而禁止这种类型参数的使用。
static_assert 则在布尔判断失败时把后面的字符串作为消息内容报告为编译错误。
在编译时，每个被使用的封闭泛型类型（即是所有泛型参数的实际类型都已被指明的泛型）都会有独立的编码产生，编译程序会在此时确保类型安全性。可是如果泛型要运用其泛型参数的某成员，而该泛型参数又不包含该成员的时候，编译程序所产生的错误信息或会看似与实际问题无关，增加除错的难度。