参考: http://www.oracle.com/technetwork/cn/articles/java/juneau-generics-2255374-zhs.html
是什么
场景:希望有一个容器,可以接受任意类型
基本实现
文档中首先提出了一种实现方式
public class ObjectContainer {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
但是这种方式不是合适的解决方案。这种方式不是类型安全的,且要求在检索封装的对象的时候使用显示类型转换。这就有可能引发异常
使用泛型来处理这种问题
public class GenericContainer<T> {
private T obj;
public GenericContainer(){} //无参构造
public GenericContainer(T t){ //有参构造
obj = t;
}
public T getObj(){
return obj;
}
public void setObj(T t){
obj = t;
}
}
这时候,不确定的类型就不是Object了,而是T,这是泛型类型
如果我们创建了一个这类容器,且指定了类型,那么就不能再在里面存放别的类型的对象
这里的描述我更倾向于:https://segmentfault.com/a/1190000005179142里面的说法:
用一个类来包装一个变量,但是我们不确定变量类型的时候使用泛型。也称为[泛型类]。
使用泛型的好处
1.更强的类型检查。可以理解为因为指定了类型,就避免了其他类型的加入,避免发生类型转换错误
2.因为指定了类型,编译器明确知道集合中的数据类型,我们就可以直接使用对象调用其方法:意思就是说比如内部是String类型,我们就可以直接拿对象调用String的方法,无需再进行显示类型转换
如何使用泛型
上面的示例是生成泛型对象类型的用例
<T>是一个类型参数,表示在运行时,为这个类分配了这个类型,并且可以在整个类中使用
根据惯例,下面给出了常用的类型参数:
- E:元素
- K:键
- N:数字
- T:类型
- V:值
- S、U、V 等:多参数情况中的第 2、3、4 个类型
泛型可以用于构造函数的参数中,限制参数类型
如果一个类有多个类型参数,声明的时候,类型参数之间使用“,”分隔,如:
public class GenericContainer<T,S,E> {...}
这个就表示我这个类可以接收多个类型的参数
有界类型
情况是,我们希望控制类型参数的范围,而不是任何类型,常用方式就是在类型参数部分使用extends或super关键字,限制泛型类型的边界
比如:
//表示类型参数T属于Number的子类,指定了类型参数的上界
public class GenericNumberContainer <T extends Number>{...}
//这个我暂时没有找到例子,按照上面的理解就是这个泛型类型是T的父
//类,对应的,也就指定了类型参数的下界,至少也要是T的父类,待证
public class XXX<? super T>{...}
泛型方法
- 有时我们不知道方法将接受的类型,就可以在参数中使用泛型。
- 方法的返回类型也可以是泛型类型
在参数中使用泛型:
注意:我们要在返回值之前声明泛型类型,才能在参数中使用泛型类型
public <T> void getObj(T n){
//...
}
public static <N extends Number> double add(N a,N b){
double sum =0;
sum = a.doubleValue()+b.doubleValue();
return sum;
}
返回泛型类型
这里也需要在返回值之前声明泛型类型
public <T> T getObj(T n){
return n;
}
所以,我们在方法中需要使用到泛型的时候都要在返回值之前声明泛型类型
通配符
这里的通配符是指使用<?>来替代<T>
不推荐在返回值使用通配符,这样不安全
通配符一样可以使用extends或者super来限制上界和下界