声明:本文为原创,如有转载请注明转载与原作者并提供原文链接,仅为学习交流,本人才识短浅,如有错误,敬请指正
我的其他随笔:
来一局紧张刺激的吃鸡——浅谈装饰者模式
一起去开心的购物吧——浅谈观察者模式
记一场精彩的篮球比赛——浅谈策略模式
大家好,前几日连夜更了几篇Java设计模式的小随笔,从观看量来说,我还是很高兴的,有很多的朋友通过看了博文,也许接触了新的知识,也许理解了自己之前没弄懂的东西,也许只是加深了自己的相关方面的印象,反正不管怎么说,如果我浅薄的小随笔能在大家广阔的脑海中留下一丝丝涟漪,我都甚感荣幸。
恰逢周末,我也就不打算再更一篇重量级的设计模式相关的文章,人嘛,还是要休息的,接下来准备写得是比较繁杂的工厂模式和抽象工厂模式,敬请大家期待,如果想看之前的我的陋作的话,可以点击上面的链接。
今天呢,就简单的讲一下Java里面的泛型数组的一些小知识,属于本人的一点小总结,如果有错误的,请大家多多指正,共同进步。
在Java中,我们不能实例化(注意我说的是实例化)一个参数化类型的数组,但是却可以参数化数组本身的类型,也许大家觉得有点绕口,没有关系,我来慢慢解释,并且通过代码,让大家看的更清楚。
第一种情况,不能实例化一个参数化类型的数组,什么叫参数化类型的数组呢,就是这个数组里存储的对象是参数化类型,大家比较熟悉的List<String>就是一个类型参数为String的参数化类型,我们在Java中也称呼它为泛型。来看代码(直接粘贴的代码没有编译器的报错指示,所以我直接截图):
我们发现报错了,报错信息就是Java无法创建参数化类型的数组。
那么为什么Java会禁止我们做这样的事呢,《Thinking in java》一书中指出,由于泛型具有擦除机制,在运行时的类型参数会被擦除,Java只知道存储的对象是一个Object而已,而对于Java的数组来说,他必须知道它持有的所有对象的具体类型,而泛型的这种运行时擦除机制违反了数组安全检查的原则。
那么有其他可以曲线救国的方法吗,注意我之前所说,虽然我们不能实例化一个参数化类型的数组,但是编译器也只是检查实例化而已,而对于创建一个参数化类型数组的引用,却并不会报错。
所以我们可以通过创建一个非参数化类型的数组,然后将他强制类型转换为一个参数化类型数组。即:
然后我们就会发现编译不再提示报错,我们来使用一下看看。
正常传入一个String类型参数的list并不会有任何问题,但当我们传入一个类型参数为Integer的list时编译器却提示我们有错,报错原因是类型不合法,数组期望一个List<String>,我们却传入了List<Integer>,由此我们知道,通过强转型实现的参数化类型数组,Java已经获悉了这个数组在运行时应该持有的具体类型,因此他是一个合法的数组。
这是第一种情况,我们不能实例化参数化类型的数组。
第二种情况,我们可以参数化数组本身的类型。
参数化数组本身的类型,顾名思义,我们不再参数化数组持有的对象的类型,而是将数组应该存储的对象进行参数化,我们来看一个返回一个数组的参数化方法:
在该参数化方法中,我们传入了一个数组,返回该数组本身,唯一的引人注目的地方就是数组中的对象类型为泛型。
我们来简单的测试一下。
其中JR类为我建的一个简单类,重写了toString方法便于查看,而不是让他默认打印对象地址。
下面是运行结果。
我们发现,无论我们传入Integer类型数组或String类型数组或自定义对象数组,该参数化方法总能正确的执行,即数组本身的类型被参数化了,但在运行时,被赋予了具体的类型。
事实上,即使我们能参数化数组本身的类型,我们也不能直接创建一个泛型数组,这在编译时都不被允许。
注意红色波浪线。
我们可以通过创建Object数组然后将其强转型为T[ ]来近似实现我们的目的,但这是没有意义的。
因为在这种情况下,任何Object类型及其子类,也就是除了基本类型之外的所有Java对象都可以放入这个数组中。
通过以上的研究,我们可以发现,想将泛型与数组联系起来使用是一件既危险又容易自讨没趣的苦差事,所以在日常使用中,我们最普遍使用泛型的情况就是与Collection与Map联系使用,以协助我们快速发现错误而不是等到运行时才报出一大串异常。
谢谢大家,今天的泛型数组的相关内容大致就说到这里了,有问题的话大家可以在下面评论区交流哦。