泛型是什么
所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。
我们为什么要使用泛型呢?数据类型为什么要使用"宽泛"的?
设想一下 , 如果我们没有泛型 , 那么我们在使用List的时候, 经常使用到的操作就是存和取 , 但是我们因为不能指定泛型 , 所以只能存入Object类型.
- 存数据
list.add(new Person());
恩 , 没有多大的影响 , 转型操作让我们很舒服 , 但是取数据就没这么方便了 - 取数据
Person p = (Person) list.get(0)
每次取出数据都要先进行强制类型转换 , 转来转去的很快你就会迷糊 .
所以 , 我们现在引入了泛型之后 , 对于List的操作就方便多了
随便说一下
其实 , 在Java中使用的泛型也不是真正意义上的泛型 , 因为我们在编译之后 , 再反编译回java代码的话 , 可以看到编译器自动的把我们的泛型操作还原回了强制类型转换 , 所以我们吧java中的泛型叫做伪泛型 , 把它当做语法糖就好,
泛型使用
首先准备好我们的测试对象Box:
public class Box<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
- 直接使用泛型
这种方式就像普通的List一样 , 规定了数据结构之后 , 直接使用 .
Box<Number> b=new Box<>();
b.setData(new Double(1.1));
Number data = b.getData();
我们也可以在源码中找到类似的使用:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
其实这种方式和直接使用Object挺像的 , 只是略微灵活了一些 . 但是这就满足了么? 我们可以使用另外一种更舒服更优雅的方法
public ArrayList(Collection<? extends E> c) {
... ...
}
- 设置类型上限<? extends Number>
用这种方法 , 就可以限定使用泛型的上限了 , 什么叫上限呢 , 就是继承关系的小于 , 不是小于等于 拿ArrayList来举例子
public class ArrayList<E> extends AbstractList<E>
首先,在ArrayList的类定义中就生命了使用泛型E , 那么我们在实例化的时候 , 就规定了E的实际类型 .
public boolean addAll(int index, Collection<? extends E> c) {
if (index < 0 || index > this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
int cSize = c.size();
if (cSize==0)
return false;
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
parent.addAll(parentOffset + index, c);
this.modCount = parent.modCount;
this.size += cSize;
return true;
}
addAll方法中 , 有这样一个限定<? extends E> , 也就是说 , addAll方法允许接收一个集合 , 集合的泛型类型必须是E的子类 . 但必须注意的是 , 这里设置了类型的上限 , 如果超出上限的话 ,会抛出异常的 .
- 设置类型下限<? super Number>
这个和第二点正好相反 , 限定了泛型的类型下限(好像没见过这么玩的)
父类的引用可以指向子类的实例 , 子类的引用无法指向父类的实例
Box<? super Number> box=new Box<>();
box.setData(new Object());
/**
*这里会报错 , 因为Object为Number的父类 , 虽然限定了? super Number ,但作为参数 ,
*子类无法指向父类的应用, 即Object不能当成Number使用
**/
box.setData(new Integer(1));
/**
*这里与上面恰好相反 , Integer可以当成Number使用 , 编译通过
*/
乍一看好像有点乱是吧 , 其实在泛型的默认规范中 , 如果破坏了这个规范 , 那么使用泛型就没有太大的意义了
- extends , 适用于get()方法 , 用来限制返回值类型
- super 适用于set()方法 , 用来限制参数类型
网友评论