Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » Java SE 综合讨论区  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 关于泛型——java参数化类型的浅析
dzm521





发贴: 12
积分: 0
于 2006-06-09 23:54 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
大家都知道Vector以及其他的容器可以不加任何修饰地存储任何类型的对象,这给我们带来了极大的方便,也使得容器很容易被复用,但是大多数时候我们可能需要只能存储某一类型对象的Vector,这是因为我们不希望由于自己失误或其他原因在Vector中添加(add())了不同类型的对象而导致在程序中其它地方的get()发生运行时异常(这是由于不正确的类型转化引发的),请看下面的例子:
//:TestVector.java
import 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.java

import 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.java
public 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<E> v = new Vector<E>(); E在此处代表我们指定v中只能存放E这种类型的对象,这样将确保我们不会错误地将别的类型的对象添加进去,如果你非要那样做错,编译器也不会允许,并且我们在使用get()方法的时候也不需要向下转型为对象本身的类型E,因为编译器已经为我们完成了,它很清楚地知道v中存储的对象类型就是E,而且get()返回的对象类型就是E而不光是Object。试试下面的例子:
//: TestVector2.java

import java.util.Vector;
public class TestVector2 {
public static void main(String[] args) {
Vector<Dog> v = new Vector<Dog>();
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++中模板的概念。(如果你发现此贴中有不准确的地方,望及时指正,以免误人!谢谢!)



好的程序设计语言能帮助程序员用它写出好程序,但无论哪种语言都避免不了程序员用它写出了坏程序。

话题树型展开
人气 标题 作者 字数 发贴时间
8769 关于泛型——java参数化类型的浅析 dzm521 3228 2006-06-09 23:54
8023 Re:关于泛型——java参数化类型的浅析 dzm521 108 2006-06-10 00:20

flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923