浅析类、含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类的三个局限:
- 使用时需要将Object类型的数据强行转换成所需数据,如上图中的“float temp=(float)firstQueue.DeQueue()”,该语句将Obejct类型的数据强行转换成float类型的数据。
- 强行转换容易出错 ,且在集成开发环境(如Visual Studio)中,还有编译器中是不报错的,只有在运行时才报错
- 强行转换是有额外开销的
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类一定比普通类要好。他们只是适用的情况不同,仅此而已。结合到某一具体实例,才可以分析它们三者中谁是最优的。