学习系列之泛型

一、泛型的是什么

  泛型的英文解释为generic,当然我们查询这个单词时,更多的解释是通用的意思,然而有些人会认为明明是通用类型,怎么成泛型了的,其实这两者并不冲突的,泛型本来代表的就是通用类型,只是微软可能有一个比较官方的此来形容自己引入的特性而已,既然泛型是通用的, 那么泛型类型就是通用类型的,即泛型就是一中模子。 在生活中,我们经常会看到模子,像我们平常生活中用的桶子就是一个模子,我们可以用桶子装水,也可以用来装油,牛奶等等,然而把这些都装进桶子里面之后,它们都会具有桶的形状(水,牛奶和油本来是没有形的),即具有模子的特征。同样,泛型也是像桶子一样的模子,我们可以用int类型,string类型,类去实例化泛型,实例化之后int,string类型都会具有泛型类型的特征就是说可以使用泛型类型中定义的方法,如List<T>泛型,如果用int去初始化它后,List<int>的实例就可以用List<T>泛型中定义的所有方法,用string去初始化它也一样,和我们生活中的用桶装水,牛奶,油等非常类似

二、C# 2.0为什么要引入泛型

  大家通过第一部分知道了什么是泛型,然而C#2.0中为什么要引入泛型的?这答案当然是泛型有很多好处的。下面通过一个例子来说明C# 2.0中为什么要引入泛型,然后再介绍下泛型所带来的好处有哪些。

    当我们要写一个比较两个整数大小的方法时,我们可能很快会写出下面的代码:

public class Compare
    {
        // 返回两个整数中大的那一项
        public static int Compareint(int int1, int int2)
        {
            if (int1.CompareTo(int2) > 0)
            {
                return int1;
            }

            return int2;
        }
    }

然而需求改变为又要实现比较两个字符串的大小的方法时,我们又不得不在类中实现一个比较字符串的方法:

如果需求又改为要实现比较两个对象之间的大小时,这时候我们又得实现比较两个对象大小的方法,然而我们中需求中可以看出,需求中只是比较的类型不一样的,其实现方式是完全一样的,这时候我们就想有没有一种类型是通用的,我们可以把任何类型当做参数传入到这个类型中去实例化为具体类型的比较,正是有了这个想法,同时微软在C#2.0中也想到了这个问题,所以就导致了C#2.0中添加了泛型这个新的特性,泛型就是——通用类型,有了泛型之后就可以很好的帮助我们刚才遇到的问题的,这样就解决了我们的第一个疑问——为什么要引入泛型。下面是泛型的实现方法:

public class Compare<T> where T : IComparable
    {
        public  static T CompareGeneric(T t1, T t2)
        {
            if (t1.CompareTo(t2) > 0)
            {
                return t1;
            }
            else
            {
                return t2;
            }
        }
    }

这样我们就不需要针对每个类型实现一个比较方法,我们可以通过下面的方式在主函数中进行调用的:

public class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Compare<int>.CompareGeneric(3, 4));
            Console.WriteLine(Compare<string>.CompareGeneric("abc", "a"));
            Console.Read();
        }
    }

通过上面的代码大家肯定可以理解C# 2.0中为什么要引入泛型的,然而泛型可以给我们带什么好处的呢?从上面的例子可以看出,泛型可以帮助我们实现代码的重用,大家很清楚——面向对象中的继承也可以实现代码的重用,然而泛型提供的代码的重用,确切的说应该是 “算法的重用”(我理解的算法的重用是我们在实现一个方法中,我们只要去考虑如何去实现算法,而不需要考虑算法操作的数据类型的不同,这样的算法实现更好的重用,泛型就是提供这样的一个机制)。

我们在来看一个熟悉的算法——冒泡排序,冒泡排序中我们可以对不同类型的数据进行排序,其中,基本的算法逻辑是完全相同的,仅仅是数据类型的不同,我们为了适应程序的灵活性,和重用性,我们可以使用泛型来定义一个排序的模子,对多种数据类型进行排序。

class Program
    {
        static void Main(string[] args)
        {
            int[] array = {12,23,16,32,89,5};
            SortHelper<int> sort = new SortHelper<int>();
            sort.BubbleSort(array, (a,b) => a > b);
            Console.ReadKey();
        }
    }

    public delegate bool Contrast<T>(T t1, T t2);//传入两个参数来作比较 

    public class SortHelper<T>
    {
        public  void BubbleSort( T [] array, Contrast<T> contrast)
        {
            for (int i = 0; i < array.Length - 1; i++)
            {
                for (int j = 0; j < array.Length - 1-i; j++)
                {
                    if (contrast(array[j] , array[j + 1]) )
                    {
                        T temp = array[j];
                        array[j] = array[j+1];
                        array[j+1] = temp;
                    }
                }
            }
            Console.WriteLine("排序后的数组");
            for (int i = 0; i < array.Length - 1; i++)
            {
                Console.WriteLine("{0}", array[i]);
            }
        }
    }

运行结果:

然而泛型除了实现代码的重用的好处外,还有可以提供更好的性能和类型安全,下面通过下面一段代码来解释下为什么有这两个好处的。

class Program
    {
        public static int constintListSize = 500000;
        static void Main(string[] args)
        {
            UseArrayList();
            UseGenericList();
            Console.ReadKey();
        }
        private static void UseArrayList()
        {
            ArrayList list = new ArrayList();
            long startTicks = DateTime.Now.Ticks;
            for (int i = 0; i < constintListSize; i++)
            {
                list.Add(i);
            }

            for (int i = 0; i < constintListSize; i++)
            {
                int value = (int)list[i];
            }
            long endTicks = DateTime.Now.Ticks;
            Console.WriteLine("使用ArrayList,耗时:{0} ticks", endTicks - startTicks);
        }

        private static void UseGenericList()
        {
            List<int> list = new List<int>();
            long startTicks = DateTime.Now.Ticks;
            for (int i = 0; i < constintListSize; i++)
            {
                list.Add(i);
            }
            for (int i = 0; i < constintListSize; i++)
            {
                int value = list[i];
            }
            long endTicks = DateTime.Now.Ticks;
            Console.WriteLine("使用List<int>,耗时:{0} ticks", endTicks - startTicks);
        }
    }

泛型能够提供的另一个好处就是类型安全,这是什么意思呢?看下面一段代码:

ArrayList list = new ArrayList();
int i = 100;
list.Add(i);
string value = (string)list[0];

有读者一眼就可以看出这段代码有问题,因为类型不匹配,添加到ArrayList中的是一个int类型,而获取时却想将它转换为string类型。 可惜的是,编译器无法知道,因为对它来说,不管是int也好,string也好,它们都是Object类型。 在编写代码时,编译器提供给开发

者的最大帮助之一就是可以检查出错误,也就是常称的编译时错误(Compile timeerror)。 当使用ArrayList时,对于上面的问题,编译器无能为力,因为它认为其是合法的,编译可以顺利通过。 这种错误有时候隐藏在程序中很难发现,最糟糕的情况是产品已经交付用户,而当用户在使用时不巧执行到这段代码,便会抛出一个异常,这时的错误,称为运行时错误(Runtime error)。

通过使用泛型集合,这种情况将不复存在,当试图进行类似上面的转换时,根本无法通过编译,这样有助于尽早发现问题:

List<int> list = new List<int>();
int i = 100;
list.Add(i);
string value = (string)list[0]; //编译错误
时间: 2024-11-05 11:35:46

学习系列之泛型的相关文章

好程序员大数据学习路线分享Scala系列之泛型

好程序员大数据学习路线分享Scala系列之泛型,带有一个或多个类型参数的类是泛型的. 泛型类的定义: //带有类型参数A的类定义class Stack[A] {private var elements: List[A] = Nil//泛型方法def push(x: A) { elements = x :: elements }def peek: A = elements.headdef pop(): A = {val currentTop = peekelements = elements.ta

JDK源代码学习系列04----ArrayList

                                                                         JDK源代码学习系列04----ArrayList 1.ArrayList简单介绍 ArrayList是基于Object[] 数组的,也就是我们常说的动态数组.它能非常方便的实现数组的添加删除等操作. public class ArrayList<E> extends AbstractList<E> implements List<

【深度学习系列4】深度学习及并行化实现概述

[深度学习系列4]深度学习及并行化实现概述 摘要: 深度学习可以完成需要高度抽象特征的人工智能任务,如语音识别.图像识别和检索.自然语言理解等.深层模型是包含多个隐藏层的人工神经网络,多层非线性结构使其具备强大的特征表达能力和对复杂任务建模能力.训练深层模型是长期以来的难题,近年来以层次化.逐层初始化为代表的一系列方法的提出给训练深层模型带来了希望,并在多个应用领域获得了成功.深层模型的并行化框架和训练加速方法是深度学习走向实用的重要基石,已有多个针对不同深度模型的开源实现,Google.Fac

Android学习系列(17)--App列表之圆角ListView(续)

http://www.cnblogs.com/qianxudetianxia/archive/2011/09/19/2068760.html 本来这篇文章想并到上篇Android学习系列(16)--App列表之圆角ListView中的,但是若是如此就让大家错过一篇新的好的文章,着实可惜.上篇中我们使用shape,corners,gradient实现了一个渐变的圆角效果,但是在完文之后的实践中,我发现有时效果不甚满意,选中和放手的事件监听没有去正确的判断,然后渐变效果也比较单一,性能也觉得不是很快

ASP.NET MVC学习系列(二)-WebAPI请求

继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetU

Caffe学习系列——工具篇:神经网络模型结构可视化

Caffe学习系列--工具篇:神经网络模型结构可视化 在Caffe中,目前有两种可视化prototxt格式网络结构的方法: 使用Netscope在线可视化 使用Caffe提供的draw_net.py 本文将就这两种方法加以介绍 1. Netscope:支持Caffe的神经网络结构在线可视化工具 Netscope是个支持prototxt格式描述的神经网络结构的在线可视工具,网址:  http://ethereon.github.io/netscope/quickstart.html  它可以用来可

Intelli IDEA学习系列之快捷键篇

Intelli IDEA学习系列之快捷键篇 IDEA简介: IDEA 全称IntelliJ IDEA,是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支持.Ant.JUnit.CVS整合.代码审查. 创新的GUI设计等方面的功能可以说是超常的.IDEA是JetBrains公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主. 在学习过程中会慢慢补充..... [1.查找] 1

Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问

本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这部分内容需要以下Jar包支持 mysql-connector:MySQL数据库连接驱动,架起服务端与数据库沟通的桥梁: MyBatis:一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架: log4j:Apache的开源项目,一个功能强大的日志组件,提供方便的日志记录: 修改后的pom.xm

Oracle学习系列4

Oracle学习系列4 ************************************************************************************ 数据库更新操作: 分类: 查询操作:select 更新操作:insert ,update , delete 为了保存原始的emp表的信息,在进行增删改之前备份词表: create table emp_bak as select * from emp ; //将表emp结构和数据完整的复制出来 添加数据: