一、泛型的作用
泛型是.net中十分常见的一种特性。它是在.net 2.0的时候加入。那为什么要在.net 2.0的时候加入泛型这个特性呢?我们首先来看一段代码。

using System;

namespace 泛型

{

    class Program

    {

        static void Main(string[] args)

        {

            int iParameter = 1;

            string sParameter = "hello world";

            DateTime dtParameter = DateTime.Now;

            Console.WriteLine("***************************最开始的写法*********************************");

            CommonMethod.ShowInt(iParameter);

            CommonMethod.ShowString(sParameter);

            CommonMethod.ShowDateTime(dtParameter);

            Console.ReadLine();

        }

    }

}
using System;

using System.Collections.Generic;

using System.Text;

namespace 泛型

{

    public class CommonMethod

    {

        public static void ShowInt(int iParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), iParameter.ToString(), iParameter.GetType().ToString()));

        }

 

        public static void ShowString(string sParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), sParameter.ToString(), sParameter.GetType().ToString()));

        }

 

 

        public static void ShowDateTime(DateTime dtParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}",typeof(CommonMethod), dtParameter.ToString(), dtParameter.GetType().ToString()));

        }

    }

}

通过代码可以理解,我们只是要根据不同的类型,输出相同的内容。因为.net 1.0的时候没有泛型的概念,那么我们最简单的做法就是有多少类型,我们就写多少个方法,进行输出。

这样就会造成一些问题:

1、代码量大。.net有那么多类型,每一个类型都写一个方法,那么代码势必会很长。

2、不利于代码维护。当需要对输出内容进行修改时,则每一个方法都需要进行修改。这就是一种灾难。

那么有没有方法解决这些问题呢?

在.net 1.0的时候,我们可以通过这种方式进行解决。先上代码:

using System;

namespace 泛型

{

    class Program

    {

        static void Main(string[] args)

        {

            int iParameter = 1;

            string sParameter = "hello world";

            DateTime dtParameter = DateTime.Now;

            Object oParameter = "Object";

            Console.WriteLine("***************************.net 1.0 最开始的写法*********************************");

            CommonMethod.ShowInt(iParameter);

            CommonMethod.ShowString(sParameter);

            CommonMethod.ShowDateTime(dtParameter);

            Console.WriteLine("***************************.net 1.0 优化的写法*********************************");

            CommonMethod.ShowObject(iParameter);

            CommonMethod.ShowObject(sParameter);

            CommonMethod.ShowObject(dtParameter);

            CommonMethod.ShowObject(oParameter);

            Console.ReadLine();

        }

    }

}
using System;

using System.Collections.Generic;

using System.Text;

namespace 泛型

{

    public class CommonMethod

    {

        public static void ShowInt(int iParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), iParameter.ToString(), iParameter.GetType().ToString()));

        }

 

        public static void ShowString(string sParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), sParameter.ToString(), sParameter.GetType().ToString()));

        }

 

 

        public static void ShowDateTime(DateTime dtParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}",typeof(CommonMethod), dtParameter.ToString(), dtParameter.GetType().ToString()));

        }

 

        public static void ShowObject(Object oParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}",typeof(CommonMethod), oParameter.ToString(), oParameter.GetType().ToString()));

        }

    }

}

代码中添加了ShowObject方法,参数传递Object类型,然后所有的类型都调用这个方法。那么结果呢?

带泛型的类能作为spring的组件吗_泛型

运行结果是正常的。那么为什么可以这样?

1、任何父类出现的地方都可以用子类代替。

2、Object是一切类型的父类

感觉可以使用这个方法解决之前不同类型,输出相同内容的问题了。为什么后来又出现了泛型呢?

因为使用Object的方法,有两个问题:

1、装箱和拆箱的性能损耗。object是引用类型,当传递值类型时,需要转换成引用类型。

传入一个Int值(栈)需要把值从栈Copy堆里面

2、类型安全问题。当你需要传递一个int类型时,你传递了一个String类型。编译是能通过的,只有等到运行时才会报错。这是不安全的。

总结起来在.net 1.0的时代,主要有几个问题:

1、代码重复比较严重。不同的类型需要写不同的方法,造成代码冗余严重。

2、使用Object参数的形式能解决代码冗余的问题,但是性能上付出了代价。

3、使用Object参数的形式,参数类型是不安全的。任何类型的参数都能传递到方法里。

所以,为了解决这些问题,在.net 2.0的时候就引入了泛型这个特性。

还是一样,先上代码:

using System;

namespace 泛型

{

    class Program

    {

        static void Main(string[] args)

        {

            int iParameter = 1;

            string sParameter = "hello world";

            DateTime dtParameter = DateTime.Now;

            Object oParameter = "Object";

            Console.WriteLine("***************************.net 1.0 最开始的写法*********************************");

            CommonMethod.ShowInt(iParameter);

            CommonMethod.ShowString(sParameter);

            CommonMethod.ShowDateTime(dtParameter);

            Console.WriteLine("***************************.net 1.0 优化的写法*********************************");

            CommonMethod.ShowObject(iParameter);

            CommonMethod.ShowObject(sParameter);

            CommonMethod.ShowObject(dtParameter);

            CommonMethod.ShowObject(oParameter);

            Console.WriteLine("***************************.net 泛型*********************************");

            CommonMethod.Show<int>(iParameter);

            CommonMethod.Show<string>(sParameter);

            CommonMethod.Show<DateTime>(dtParameter);

            CommonMethod.Show<Object>(oParameter);

            Console.ReadLine();

        }

    }

}
using System;

using System.Collections.Generic;

using System.Text;

namespace 泛型

{

    public class CommonMethod

    {

        public static void ShowInt(int iParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), iParameter.ToString(), iParameter.GetType().ToString()));

        }

 

        public static void ShowString(string sParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), sParameter.ToString(), sParameter.GetType().ToString()));

        }

 

 

        public static void ShowDateTime(DateTime dtParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), dtParameter.ToString(), dtParameter.GetType().ToString()));

        }

 

        public static void ShowObject(Object oParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), oParameter.ToString(), oParameter.GetType().ToString()));

        }

 

        public static void Show<T>(T tParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), tParameter.ToString(), tParameter.GetType().ToString()));

        }

    }

}

注意里面Show的方法,这个就是泛型方法的定义。那么运行结果呢?请看图:

带泛型的类能作为spring的组件吗_泛型缓存_02

可以看到是没有问题的。

泛型的作用是什么?我用一句话概括就是不同类型的参数进行相同的操作时,你就可以考虑使用泛型。

二、泛型的定义

public static void Show<T>(T tParameter)

        {

            Console.WriteLine(string.Format("这个方法是:{0},它的参数是{1},参数的类型是{2}", typeof(CommonMethod), tParameter.ToString(), tParameter.GetType().ToString()));

        }

泛型方法与一般方法的区别在方法名后有一对<>。其中T表示的是一个占位符,意思是我这里会指定一个类型,但是我现在不知道,我把位置给占着。等要使用到这个方法时,我在指定类型。其采用的思想延迟思想。

其中占位符可以是一个,也可以是多个。比如Show<T,N,M,Two>都行。但是请注意,这里的占位符不能是关键词。比如class,static等。

三、泛型有没有解决问题?

第一个问题,代码冗余,这个比较明显,在main方法里面都调用了一个方法,代码简洁不少。

第二个性能问题,那我们就写一个测试代码。

首先添加一个类Monitor。代码如下:

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Text;

namespace 泛型

{

    public class Monitor

    {

        public static void Show()

        {

            Console.WriteLine("****************Monitor******************");

            {

                int iValue = 12345;

                long commonSecond = 0;

                long objectSecond = 0;

                long genericSecond = 0;

                {

                    Stopwatch watch = new Stopwatch();

                    watch.Start();

                    for (int i = 0; i < 100000000; i++)

                    {

                        ShowInt(iValue);

                    }

                    watch.Stop();

                    commonSecond = watch.ElapsedMilliseconds;

                }

                {

                    Stopwatch watch = new Stopwatch();

                    watch.Start();

                    for (int i = 0; i < 100000000; i++)

                    {

                        ShowObject(iValue);

                    }

                    watch.Stop();

                    objectSecond = watch.ElapsedMilliseconds;

                }

                {

                    Stopwatch watch = new Stopwatch();

                    watch.Start();

                    for (int i = 0; i < 100000000; i++)

                    {

                        Show<int>(iValue);

                    }

                    watch.Stop();

                    genericSecond = watch.ElapsedMilliseconds;

                }

                Console.WriteLine("一般方法耗时={0}毫秒,Object方法耗时={1}毫秒,泛型方法耗时={2}毫秒" , commonSecond, objectSecond, genericSecond);

            }

        }

 

        #region PrivateMethod

        private static void ShowInt(int iParameter)

        {

            //do nothing

        }

        private static void ShowObject(object oParameter)

        {

            //do nothing

        }

        private static void Show<T>(T tParameter)

        {

            //do nothing

        }

        #endregion

    }

}

main方法:

using System;

namespace 泛型

{

    class Program

    {

        static void Main(string[] args)

        {

            for (int i = 0; i < 5; i++)

            {

                Monitor.Show();

            }

            Console.ReadLine();

        }

    }

}

Monitor类中定义了ShowInt,ShowObject,Show三类方法,每个方法内都是空的,没有做任何操作。然后在Show方法中,调用ShowInt,ShowObject,Show各100000000次,通过Stopwatch计时器计算每个方法执行10000000次所需要的时间(毫秒)。

Main方法中,为了比较全面的看到时间,我这里调用了5次Show方法。结果如图:

带泛型的类能作为spring的组件吗_泛型缓存_03

明显的能看出,Object方法耗时最长,一般方法的耗时和泛型的耗时基本相差无几。

所以在性能上的问题,我们也能得到了解决。

第三个问题:类型安全问题。

当我们使用泛型方法时,在调用的适合就需要指定类型。

int iValue = 12345;

string sValue=”Hello World”;

Show(iValue)

这样是可以成功的,但是如果我们写成这样:

Show(sValue)

则编译不通过,从一定程度上解决了类型安全的问题。

四、泛型缓存

为什么泛型的效率这么高呢?这里面涉及到泛型缓存的概念。

类中的静态类型无论实例化多少次,在内存中只会有一个。静态构造函数只会执行一次。在泛型类中,T类型不同,每个不同的T类型,都会产生一个不同的副本,所以会产生不同的静态属性、不同的静态构造函数。简单的说就是不同类型的T会生成相同的副本,而相同类型的T会只用同一个副本。

请看下面的例子:

GenericCache类:

using System;

using System.Collections.Generic;

using System.Text;

 

namespace 泛型

{

    public class GenericCache<T>

    {

        static GenericCache()

        {

            Console.WriteLine("这是 GenericCache 静态构造函数");

            _TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));

        }

        private static string _TypeTime = "";

        public static string GetCache()

        {

            return _TypeTime;

        }

    }

}

GenericCacheTest类:

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

namespace 泛型

{

    public class GenericCacheTest

    {

        public static void Show()

        {

            for (int i = 0; i < 5; i++)

            {

                Console.WriteLine("这是第{0}次执行......", (i + 1).ToString());

                Console.WriteLine(GenericCache<int>.GetCache());

                Thread.Sleep(100);

                Console.WriteLine(GenericCache<long>.GetCache());

                Thread.Sleep(100);

                Console.WriteLine(GenericCache<DateTime>.GetCache());

                Thread.Sleep(100);

                Console.WriteLine(GenericCache<string>.GetCache());

                Thread.Sleep(100);

                Console.WriteLine(GenericCache<GenericCacheTest>.GetCache());

                Thread.Sleep(100);

            }

        }

    }

}

main方法:

using System;

namespace 泛型

{

    class Program

    {

        static void Main(string[] args)

        {

            GenericCacheTest.Show();

            Console.ReadLine();

        }

    }

}

运行后结果为:

带泛型的类能作为spring的组件吗_泛型缓存_04

观察结果可以看到,5次执行相同类型的时间都是一致的。并且从第二次开始,执行时并没有进入构造函数。利用泛型的这一个特性,可以实现缓存。

注意:只能为不同的类型缓存一次。泛型缓存比字典缓存效率高。泛型缓存不能主动释放