展开全部
大家都知道Vector以及其他的容器可以不加任何修饰地e68a8462616964757a686964616f31333236373765存储任何类型的对象,这给我们带来了极大的方便,也使得容器很容易被复用,但是大多数时候我们可能需要只能存储某一类型对象的Vector,这是因为我们不希望由于自己失误或其他原因在Vector中添加(add())了不同类型的对象而导致在程序中其它地方的get()发生运行时异常(这是由于不正确的类型转化引发的),请看下面的例子:
//:TestVector.javaimport java.util.Vector;class Dog{ private int number; public Dog(int number){ this.number = number; } public String toString(){ return "This is number #: " + number; }}public class TestVector { public static void main(String[] args) { Vector v = new Vector(); Dog dog; v.add(new Dog(1)); v.add(new Dog(2)); v.add(new Dog(3)); v.add(new Integer(4)); //假设由于我的疏忽,错误地将Integer类型的对象添加进了v中 for(int j = 0; j < v.size(); j++){ dog = (Dog)v.get(j); //想一想,当取到类型为Integer的对象时将引起ClassCastException System.out.println(dog); } }}
注意带有注释的那两行,这种错误在编译时并不会提醒我们,只能在运行时发生ClassCastException,这是(Dog)v.get(j)引起的,更糟糕的是当发生这种错误之后我们很难找到错误的根源在哪里,换句话说就是我们到底在哪里错误地添加了那个非Dog类型的Integer对象,大家运行程序就会明白。尤其是当我们在离那个错误的v.add(new Integer(4))很远的地方(可能是很多层)调用(Dog)v.get(i)时更是如此。此时大家可能会想,如果限制v仅能添加Dog类型的对象,问题不就解决了吗?这的确是个办法,解决如下:
//: DogVector.javaimport java.util.Vector;public class DogVector { private Vector v = new Vector(); public void add(Dog dog){ v.add(dog); } public Dog get(int index){ return (Dog)v.get(index); } public int size(){ return v.size(); }}//:TestDogVector.javapublic class TestDogVector { public static void main(String[] args) { Dog dog; DogVector dv = new DogVector(); //明确地创建了只能存放Dog对象的DogVector dv.add(new Dog(1)); dv.add(new Dog(2)); dv.add(new Dog(3)); // dv.add(new Integer(4)); //此时如果再发生这种疏忽的话,编译将不能通过 for(int i = 0; i < dv.size(); i++){ dog = dv.get(i); //此处也不需要向下转型为Dog System.out.println(dog); } }}
问题得到了解决,但此时大家可能郁闷了,我们在这种情况下是不是要写很多这样乏味的代码?每一类需要存储的对象都得写一个特定的集合类吗?确实在JDK1.5以前这的确是个问题,好在JDK1.5版本中sun引进了泛型--java参数化类型,到此,想必大家已经意识到参数类型化所要解决的问题之一,就像下面这样:
Vector v = new Vector(); E在此处代表我们指定v中只能存放E这种类型的对象,这样将确保我们不会错误地将别的类型的对象添加进去,如果你非要那样做错,编译器也不会允许,并且我们在使用get()方法的时候也不需要向下转型为对象本身的类型E,因为编译器已经为我们完成了,它很清楚地知道v中存储的对象类型就是E,而且get()返回的对象类型就是E而不光是Object。试试下面的例子:
//: TestVector2.javaimport java.util.Vector;public class TestVector2 { public static void main(String[] args) { Vector v = new Vector(); Dog dog; v.add(new Dog(1)); v.add(new Dog(2)); v.add(new Dog(3)); //v.add(new Integer(4)); //此时如果再发生这种疏忽的话,编译将不能通过 for (int j = 0; j < v.size(); j++) { dog = v.get(j); //此处也不需要向下转型为Dog,方法返回类型就是Dog System.out.println(dog); } }}
通过使用参数类型化,还会发生更多的微妙的变化,这里的v.get(j)返回为Dog型只是其中一例,在上例中v的其他一些方法的参数或返回值也将发生变化,有些接收Object参数的方法此时只能接受Dog或其派生类对象,如v.Set(int Index, Dog element),注意如果使用Dog及其派生以外的Object类型的对象做参数时将发生编译期错误,这也正是我们在这种情况下想要的效果,是不是很爽呢?
好了,罗嗦了这么多,其目的就是想让大家从问题的根源来理解概念,如果大家还想对其深入的话,可以找一些专门的资料来看看,想必学过C++的朋友应该对此很容易理解,因为java的参数化类型正是借鉴了C++中模板的概念。(如果你发现此贴中有不准确的地方,望及时指正,以免误人!谢谢!)
本回答由提问者推荐
已赞过
已踩过<
你对这个回答的评价是?
评论
收起