Java泛型——原生态类型与泛型

最近在学习一些框架,有个必要的过程就是阅读源码,这是个比较需要耐心的过程,很多时候我都觉得扫一眼明白怎么个意思就行了,但越来越发现自己忽略了一件很重要的事情——代码的基本功底。很多时候在源代码里面会看到Class类似的代码,知道它是在干什么,可细说又感觉闹不明白,之前有详细看过,但都忘了,深觉不输出永远学不会。于是,重新拿起书本,想再理一理泛型相关的知识。

我想,泛型大家平时都在用,而且是业务代码必须的,写了很多却少有人关注泛型的内涵。问几个问题:
1.集合和数组的区别。
2.Java为什么引进泛型。
3.List和List有区别吗。
也许你能轻松地回答出前两个问题,那我们来看看你的答案是否正确。
答1:集合和数组最大区别就是:集合对象类型不固定且不定大小,数组定类型且长度固定。嗯,起码基本的常识还是有的。问这个问题的原因是要引出第二个问题的答案。

泛型:声明中具有一个或多个类型参数的类或接口就是泛型类或泛型接口,统称为泛型。如:List
所以你的答案是:泛型引入的目的是为了限制集合元素的类型。没错,我想大部分也停留在这个阶段了,因为我们平时写代码就只需要到这。那么,我接着问一个问题:
不限制集合的类型参数会引起什么问题呢?(摘自《Effictive Java》,只是演示,不能运行的)

//Contains only Stamp instances.
private final Collection stamps = new Collection();
stamps.add(new Coin());
for(Iterator i = stamps.iterator();i.hasNext();){
    Stamp s = (Stamp)i.next();
}

其实显而易见,这段代码在运行时会出错,因为你不可能将Coin对象转换成Stamp对象。那么问题出在哪呢?问题就在集合里面的元素只通过注释说明,但编译器并不认识注释,但一旦交由人来做这件事情就很有可能出错。 所以,我们需要一种编译时的类型检查机制,让程序员在加入不符合泛型的类型对象时报错。所以,第二问题的答案需要加入编译期的类型自动检查

每一种泛型都包含一种原生态类型,比如List的原生态类型就是List,你很少能看见代码里面用这种原生态类型的接口,基本都是泛型,这是一种规范,但是不用泛型可不可以呢? 也是可以的。

请不要在新代码中使用原生态类型:我们都知道泛型的优势,那么为什么不禁止大家使用原生态类型的代码呢?其实主要是为了保持向前的兼容性,泛型在Java1.5才出来,之前已经有大量的没有泛型的代码。这叫移植兼容性

下面就是第三个问题了,讲道理能不能绕明白还得看自己。

public static void main(String[] args){
    List strings = new ArrayList<>();
    unsafeAdd(strings, new Integer(1));
    String s = strings.get(0);
}
private static void unsafeAdd(List list, Object object){
    list.add(object);
}

编译会不会有问题呢,不会。因为原生态类型是不会检查插入对象类型的。好,那么我们改变一下写法,将List改为List

private static void unsafeAdd(List list,Object o){
        list.add(o);
    }
 
 

这样你再试试,你会发现main函数第二行报错了。下面,按照常理来思考一下,List = 集合 = 可以放任何类型的元素 = List。有问题吗?这就是我感觉一直没绕过的点。既然都Object了那还有泛型检查的必要?

嗯,首先得明确两点。
1.List和List,前者逃避了泛型检查,后者是肯定会泛型检查的。只是说,你在往List里面插入元素的时候,不管插入什么值好像都不会报错,因为Object是所有对象的父类嘛。
2.泛型是不可变的(相对于数组的协变而言)。就是说,String是Object的子类,List是List的子类, 但是List不是List的子类,那么在泛型检查的时候就会报错。

似乎是说得通的,但是更深层次的想一下,为什么泛型要设计成是不可变的呢?其实就是上面的那个问题:如果泛型不是不可变的,那么在方法参数里面,List可以加入其子类List无法控制的类型,因为在方法里面我往List里面加入Integer是合法的,但是后续你往方法里面传入什么类型的参数我是不可控的啊,要是你传入了List,还没有一种检查机制的话,那后果就不堪设想了。也就是说,如果泛型是协变的(可变的),那么List与List就一样了。

以上是我对这块知识的一点理解,结合《Effictive Java》这本书,如果有哪里不正确的,还请大家指正。下一章我们来讲讲泛型和数组。

你可能感兴趣的:(Java泛型——原生态类型与泛型)