浅析类、含Objiect的类、泛型的区别

-------要讨论这三者的区别,就得先知道它们各自的局限,下文将依次讨论类、含Object的类、泛型的局限与优点。


 

1.普通类
  普通类的局限在于当它被创建好的那一刻,它所有字段的类型,所有方法的类型都是定死了的。比如下图中的代码,是一个int型的队列。它的四个字段全都是int型。enQueue()方法的参数也是int型。出队方法DeQueue()返回值也是int型。

  当我们想要一个float队列,一个string队列,或者一个自己创建的类的队列的时候。我们必须重新写一个类。而没有办法利用之前已经写好的int型队列来减少我们的工作量。这就是普通类的局限。

public class Queue
    {
        private int head = 0, tail = 0;     //用于指向对头元素和队尾元素
        private int numElement = 0;         //数组中实际存放元素个数
        private int[] data;                 //创建一个int的数组,但还未分配空间
        private const int DEFAULTQUEUESIZE = 10; //默认队列大小
 
        public Queue()             //构造器
        {
            this.data = new int[DEFAULTQUEUESIZE];
        }
 
        public void enQueue(int item)                   //入队
        {
            if (this.numElement == this.data.Length)
            {
                throw new Exception("QUEUE FULL!");         //队满则抛出异常
            }
 
            this.data[this.head] = item;
            this.head++;
            this.numElement++;
            this.head %= this.data.Length;
        }
 
        public int DeQueue()                                    //出队
        {
            if (this.numElement == 0)
            {
                throw new Exception("QUEUE EMPTY!");            //队空则抛出异常
            }
            int temp = this.data[this.tail];
            this.tail++;
            this.tail %= this.data.Length;
            this.numElement--;
            return temp;
        }
    }

2.Object类

        想要解决这个限制的方法之一是将所有int型数据、方法改成用object型数据、方法。代码如下:

 public class ObjectQueue
    {
        private int head = 0, tail = 0;     //用于指向对头元素和队尾元素
        private int numElement = 0;         //数组中实际存放元素个数
        private Object[] data;                 //创建一个Object的数组,但还未分配空间
        private const int DEFAULTQUEUESIZE = 10; //默认队列大小
 
        public ObjectQueue()             //构造器
        {
            this.data = new Object[DEFAULTQUEUESIZE];
        }
 
        public void enQueue(Object item)                   //入队
        {
            if (this.numElement == this.data.Length)
            {
                throw new Exception("QUEUE FULL!");         //队满则抛出异常
            }
 
            this.data[this.head] = item;
            this.head++;
            this.numElement++;
            this.head %= this.data.Length;
        }
 
        public Object DeQueue()                                    //出队
        {
            if (this.numElement == 0)
            {
                throw new Exception("QUEUE EMPTY!");            //队空则抛出异常
            }
            Object temp = this.data[this.tail];
            this.tail++;
            this.tail %= this.data.Length;
            this.numElement--;
            return temp;
        }
    }

 

  如上图代码,将普通类的int类型都改成了Object类型。这样我们在就可以利用上图代码创建任意类型的队列,如float队列,string队列,还有自己创建的类型的队列等。这就是Object类的优点

  使用object类创建任意类型队列的代码如下,这里结合上图的object类和float类型举例:

ObjectQueue firstQueue =new ObjectQueue();
float item=1.5;                
firstQueue.enQueue(item);        //入队
········
float temp=(float)firstQueue.DeQueue();        //出队

  

从上图代码可以观察出Object类的三个局限

  1. 使用时需要将Object类型的数据强行转换成所需数据,如上图中的“float temp=(float)firstQueue.DeQueue()”,该语句将Obejct类型的数据强行转换成float类型的数据。
  2. 强行转换容易出错 ,且在集成开发环境(如Visual Studio)中,还有编译器中是不报错的,只有在运行时才报错
  3. 强行转换是有额外开销的

3.泛型

        想要解决Object类的局限,就需要使用泛型。接下来将使用泛型来创建队列,代码如下:

public class GenericQueue<TItem>
    {
        private int head = 0, tail = 0;     //用于指向对头元素和队尾元素
        private int numElement = 0;         //数组中实际存放元素个数
        private TItem[] data;                 //创建一个TItem的数组,但还未分配空间
        private const int DEFAULTQUEUESIZE = 10; //默认队列大小
 
        public Queue()             //构造器
        {
            this.data = new TItem[DEFAULTQUEUESIZE];
        }
 
        public void enQueue(TItem item)                   //入队
        {
            if (this.numElement == this.data.Length)
            {
                throw new Exception("QUEUE FULL!");         //队满则抛出异常
            }
 
            this.data[this.head] = item;
            this.head++;
            this.numElement++;
            this.head %= this.data.Length;
        }
 
        public TItem DeQueue()                                    //出队
        {
            if (this.numElement == 0)
            {
                throw new Exception("QUEUE EMPTY!");            //队空则抛出异常
            }
            TItem temp = this.data[this.tail];
            this.tail++;
            this.tail %= this.data.Length;
            this.numElement--;
            return temp;
        }
    }

  这里简单介绍一下泛型,上图代码中的TItem是类型参数,在具体实际应用中,它可以代替任何已有的数据类型或者我们自己创建的类型。实际使用泛型的代码如下,这里结合上图GenericQueue类和float类型举例:

//创建泛型类变量:
泛型类名<类型参数> 变量名 =new 泛型类名<类型参数>();
 
//用GenericQueue类型举例:
GenericQueue<TITem> 变量名 = new GenericQueue<TItem>();
 
//用GenericQueue类和float类型举例:
GenericQueue<float> floatQueue =new GenericQueue<TItem>();

  

结论:(泛型的优点)

        使用泛型类可以避免“Object强行转换易出错”、“Object类型强行转换需要额外时间开销”、“Object强行转换出错在编译器不报错”等问题。


 

:(接下来是我自己想说的一些话,十分浅薄,不喜勿喷)

        在我个人看来,普通类,Object类,泛型其实并没有什么绝对的高下之分,并不是说泛型一定比普通类、object类要好,或者说Object类一定比普通类要好。他们只是适用的情况不同,仅此而已。结合到某一具体实例,才可以分析它们三者中谁是最优的。

 
posted @ 2023-06-27 17:48  前进的老五  阅读(20)  评论(0编辑  收藏  举报