您的位置:首页 > 编程语言 > Java开发

为什么Java不支持创建范型数组?

2011-08-01 22:36 323 查看
最近看到BlogJava上有人在讨论为什么Java范型不支持数组http://www.blogjava.net/myqiao/archive/2005/08/08/9580.html
扩展阅读:
 http://www.blogjava.net/deepnighttwo/articles/298426.html
我想这个问题的答案是:因为这样做会破坏类型安全。核心的问题在于Java范型和C#范型存在根本区别:Java的范型停留在编译这一层,到了运行时,这些范型的信息其实是被抹掉的;而C#的范型做到了MSIL这一层。Java的做法不必修改JVM,减少了潜在的大幅改动和随之而来的风险,也许同时也反映出Java Bytecode规范在设计之初的先天不足;C#则大刀阔斧,连CLR一起改以支持更彻底的范型,换句话说,在范型这一点上,感觉C#更C++一点。
 
在Java中,Object[]数组可以是任何数组的父类,或者说,任何一个数组都可以向上转型成它在定义时指定元素类型的父类的数组,这个时候如果我们往里面放不同于原始数据类型 但是满足后来使用的父类类型的话,编译不会有问题,但是在运行时会检查加入数组的对象的类型,于是会抛ArrayStoreException:
 
String[] strArray = new String[20];
Object[] objArray = strArray;
objArray[0] = new Integer(1); // throws ArrayStoreException at runtime
 
因为Java的范型会在编译后将类型信息抹掉,这样如果Java允许我们使用类似
 
Map<Integer, String>[] mapArray = new Map<Integer, String>[20];
 
这样的语句的话,我们在随后的代码中可以把它转型为Object[]然后往里面放Map<Double, String>实例。这样做不但编译器不能发现类型错误,就连运行时的数组存储检查对它也无能为力,它能看到的是我们往里面放Map的对象,我们定义的<Integer, String>在这个时候已经被抹掉了,于是而对它而言,只要是Map,都是合法的。想想看,我们本来定义的是装Map<Integer, String>的数组,结果我们却可以往里面放任何Map,接下来如果有代码试图按原有的定义去取值,后果是什么不言自明。
 
所以,Java编译器不允许我们new范型数组。
 
其实问题的关键是Java数组的实现,当时条件艰苦,类型系统不够发达,它需要一种"简单粗暴"的方式支持协变,比方说Object[]可以是所有其他元素类型的数组比如Integer[]的父类,这样在方法签名或变量定义中可以用Object[]"通杀"所有数组。

所以Java数组就有了编译期不检查(没法检查),而在运行期保有类型信息并进行检查的行为(为类型安全),尽管这样的实现看上去既不安全,也不高效。

有了泛型,不论是否有type-erasure,我们可以在很多场合避开对类似Object[]写法的依赖,更好也更清楚的表达我们的真实意图,从这个角度讲,Java的泛型是有它积极的一面的,只是别跟数组这个老家伙较劲就好了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息