zoukankan      html  css  js  c++  java
  • 泛型

        通过使用泛型,我们可以极大地提高代码的重用度,同时还可以获得强类型的支持,避免了隐式的装箱、拆箱,在一定程度上提升了应用程序的性能。

        泛型类实例化的理论

        C#泛型类在编译时,先生成中间代码IL,通用类型T只是一个占位符。在实例化类时,根据用户指定的数据类型代替T并由即时编译器(JIT)生成本地代码,这个本地代码中已经使用了实际的数据类型,等同于用实际类型写的类,所以不同的封闭类的本地代码是不一样的。按照这个原理,我们可以这样认为:

        泛型类的不同的封闭类是分别不同的数据类型。

     

        为什么要有泛型

        它可以避免重复代码。如果有几个类或者方法类似,实现功能相同,区别只是类型不一样,如int和string是,这是可以定义一个泛型。

        泛型类就类似于一个模板,可以在需要时为这个模板传入任何我们需要的类型。

     

      由一个例子引入:

      我们在算法中会学到排序,一个很经典的排序为冒泡排序法。将几个乱序的数字用冒泡发排序,我想大多数人会很快的写出来。

      我将例子弄详细一点。新建一张aspx的页面,放一个button和一个label服务器控件,双击button,自动生成响应方法。网页关键代码如下:

    1 <asp:Button ID="Button1" runat="server" Text="对1,8,3,7,2排序" onclick="Button1_Click" />
    2 <asp:Label ID="Label1" runat="server" Text=""></asp:Label>

      要实现排序,需要现有实现冒泡排序的类,我们新建一个ShortHelper类:

     1 public class ShortHelper {
     2         public void BubbleSort(int[] array)
     3         {
     4             int length = array.Length;
     5             for(int i=0;i<=length-2;i++)
     6                 for (int j = length-1; j >= 1; j--)
     7                 {
     8                     if (array[j] < array[j - 1])
     9                     {
    10                         int temp = array[j];
    11                         array[j] = array[j - 1];
    12                         array[j - 1] = temp;
    13                     }
    14                 }
    15         }
    16 }

    将相应函数补充完整:

    protected void Button1_Click(object sender, EventArgs e)
    {
                string endsort = "";
                ShortHelper shorter = new ShortHelper();
                int[] array = { 1, 8, 3, 7, 2 };
                shorter.BubbleSort(array);
                foreach (int i in array)
                {
                    endsort += i.ToString() + ",";
                }
                int length = endsort.Length - 1;
                endsort = endsort.Substring(0, length);
                Label1.Text = endsort;
    }
    

    结果如下:

    但是,我现在又想对英文字母或者byte进行排序,怎么办呢,当然直接修改类型是可以的。但是这样会造成代码的不简洁,重用性差。现在我们就引入泛型,泛型其实就是类似于C++中的模版,是一种解决方法的同法,将类型用一个类似于占位符的代替。修改后的类如下:

     1 public class ShortHelper<T> where T : IComparable {
     2         public void BubbleSort(T[] array)
     3         {
     4             int length = array.Length;
     5             for (int i = 0; i <= length - 2; i++)
     6                 for (int j = length - 1; j >= 1; j--)
     7                 {
     8                     if (array[j].CompareTo(array[j - 1]) < 0)//因为object是没有比较大小的方法的,不用IComparable会照成无法比较大小,CompareTo方法用于比较,前一个比后一个小,返回值<0,反之返回>0
     9                     {
    10                         T temp = array[j];
    11                         array[j] = array[j - 1];
    12                         array[j - 1] = temp;
    13                     }
    14                 }
    15         }
    16 }

    在网页中添加

    1 <asp:Button ID="Button2" runat="server" Text="对f,a,s,t,v,b,e排序" onclick="Button2_Click" />
    2 <asp:Label ID="Label2" runat="server" Text=""></asp:Label>

    相应的相应函数为

     1         protected void Button1_Click(object sender, EventArgs e)
     2         {
     3             string endsort = "";
     4             ShortHelper<int> shorter = new ShortHelper<int>();   //注意此处
     5             int[] array = { 1,8,3,7,2};
     6             shorter.BubbleSort(array);
     7             foreach (int i in array)
     8             {
     9                 endsort += i.ToString() + ",";
    10             }
    11             int length = endsort.Length - 1;
    12             endsort = endsort.Substring(0, length);
    13             Label1.Text = endsort;
    14         }
    15 
    16         protected void Button2_Click(object sender, EventArgs e)
    17         {
    18             string endsort = "";
    19             ShortHelper<char> shorter = new ShortHelper<char>();   //注意此处
    20             char[] array = { 'f', 'a', 's', 't', 'v', 'b', 'e' };
    21             shorter.BubbleSort(array);
    22             foreach (char i in array)
    23             {
    24                 endsort += i + ",";
    25             }
    26             int length = endsort.Length - 1;
    27             endsort = endsort.Substring(0, length);
    28             Label2.Text = endsort;
    29         }

    运行结果为:

    当然,泛型的用法不仅仅就这,还有泛型接口,泛型方法等等。

     

        优点:

        1、性能:避免隐式的装箱和拆箱

        如AarryList(在添加数据时装箱,读取时拆箱)和List<T>区别

        2、类型安全:

        泛型的另一个特性是类型安全。与ArrayList类一样,如果使用对象,可以在这个集合中添加任意类型。下面的例子在ArrayList类型的集合中添加一个整数、一个字符串和一个MyClass类型的对象:

    1 ArrayList list = new ArrayList();
    2 list.Add(44);
    3 list.Add("mystring");
    4 list.Add(new MyClass());

      如果这个集合使用下面的foreach语句迭代,而该foreach语句使用整数元素来迭代,编译器就会编译这段代码。但并不是集合中的所有元素都可以转换为int,所以会出现一个运行异常:

    1 foreach (int i in list)
    2 {
    3     Console.WriteLine(i);
    4 }

      错误应尽早发现。在泛型类List<T>中,泛型类型T定义了允许使用的类型。有了List<int>的定义,就只能把整数类型添加到集合中。编译器不会编译这段代码,因为Add()方法的参数无效:

    1 List<int> list = new List<int>();
    2 list.Add(44);
    3 list.Add("mystring");   // compile time error
    4 list.Add(new MyClass());   // compile time error

        3、二进制代码的重用:

        泛型允许更好地重用二进制代码。泛型类可以定义一次,用许多不同的类型实例。

       类型参数约束

        程序员在编写泛型类时,总是会对通用数据类型T进行有意或无意地有假想,也就是说这个T一般来说是不能适应所有类型,但怎样限制调用者传入的数据类型呢?这就需要对传入的数据类型进行约束,约束的方式是指定T的祖先,即继承的接口或类。因为C#的单根继承性,所以约束可以有多个接口,但最多只能有一个类,并且类必须在接口之前。

        除了可以约束类型参数T 实现某个接口以外,还可以约束T 是一个结构、T 是一个类、T 拥有构造函数、T 继承自某个基类等。

        泛型方法

        在泛型方法中,泛型类型用方法声明来定义。

    1 void Swap<T>(ref T x, ref T y)
    2 {
    3   T temp;
    4   temp = x;
    5   x = y;
    6   y = temp;
    7 }

    把泛型类型赋予方法调用,就可以调用泛型方法:

    1 int i = 4;
    2 int j = 5;
    3 Swap<int>(ref i, ref j);

    但是,因为C#编译器会通过调用Swap方法来获取参数的类型,所以不需要把泛型类型赋予方法调用。泛型方法可以像非泛型方法那样调用:

    1 int i = 4;
    2 int j = 5;
    3 Swap(ref i, ref j);

    当一般方法与泛型方法具有相同的签名时,会覆盖泛型方法。

        泛型类的特性

        1、默认值:不能把null赋予泛型类型。原因是泛型类型也可以实例化为值类型,而null只能用于引用类型。为了解决这个问题,可以使用default关键字。通过default关键字,将null赋予引用类型,将0赋予值类型。

            T doc = default(T);

      2、约束:如果泛型类需要调用泛型类型上的方法,就必须添加约束。

     

    约    束

    说    明

    where T : struct

    使用结构约束,类型T必须是值类型

    where T : class

    类约束指定,类型T必须是引用类型

    where T : IFoo

    指定类型T必须执行接口IFoo

    where T : Foo

    指定类型T必须派生于基类Foo

    where T : new()

    这是一个构造函数约束,指定类型T必须有一个默认构造函数

    where T : U

    这个约束也可以指定,类型T1派生于泛型类型T2。该约束也称为裸类型约束

     

      3、继承:泛型类型可以执行泛型接口,也可以派生于一个类。泛型类可以派生于泛型基类:

    1 public class Base<T>
    2 {
    3 }
    4 public class Derived<T> : Base<T>{}

      4、静态成员:泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享。

    总结:

      泛型。通过泛型类可以创建独立于类型的类,泛型方法是独立于类型的方法。增加代码的重用性。接口、结构和委托也可以用泛型的方式创建。泛型引入了一种新的编程方式。

     

    参考资料:http://www.cnblogs.com/JimmyZhang/archive/2008/12/17/1356727.html,《C#高级编程第六版》



  • 相关阅读:
    CentOS下crontab执行java程序
    大数据学习总结(1)任务描述
    敏捷开发总结(2)开发过程活动
    敏捷开发总结(1)软件研发过程
    持续集成(4)工具对比
    持续集成(2)整体流程
    持续集成(1)概念模型
    用户画像(3)用户画像的建模方法-事实标签
    用户画像(2)构建用户画像的数据源
    用户画像(1)用户画像的概念、意义和目标
  • 原文地址:https://www.cnblogs.com/huangbx/p/2615830.html
Copyright © 2011-2022 走看看