先介绍一下泛型: java 中泛型标记符:
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
声明泛型类不能用无界通配符<?>
//编译报错
class Box<?>{
private ? item1;
private ? item2;
}
泛型擦除概念
Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除。Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。
例如:List<String>
和 List<Integer>
在编译后都变成 List
。
详见: Java 泛型擦除 - hongdada - 博客园 (cnblogs.com)
由此:当使用泛型时,泛型已经确定类型
先看如下代码:
public class tmain<T> {
public static void main(String[] args) {
tmain tmain = new tmain<RechargeRecord>();
RechargeRecord rechargeRecord = new RechargeRecord();
rechargeRecord.setOutTradeNo("123456");
tmain.processPay(new PayService<RechargeRecord>() {
@Override
public void paySuccess(String outTradeNo, RechargeRecord rechargeRecord) {
System.out.println("-----> success"+rechargeRecord.getOutTradeNo());
}
@Override
public void payFail(String outTradeNo) {
System.out.println("-----> fail"+outTradeNo);
}
}, rechargeRecord);
}
void processPay(PayService payService, T t){
payService.paySuccess("123", t);
}
}
// 泛型接口
interface PayService<T>{
void paySuccess(String outTradeNo, T t);
void payFail(String outTradeNo);
}
结果:-----> success123456
如果使用Object来写如下:
public class tmain {
public static void main(String[] args) {
RechargeRecord rechargeRecord = new RechargeRecord();
rechargeRecord.setOutTradeNo("123456");
new tmain().payProcess(new PayService() {
@Override
public void paySuccess(String outTradeNo, Object object) {
RechargeRecord rechargeRecord1 = (RechargeRecord) object;
System.out.println("-----> success"+rechargeRecord1.getOutTradeNo());
}
@Override
public void payFail(String outTradeNo) {
}
}, rechargeRecord);
}
void payProcess(PayService payService, Object object){
payService.paySuccess("12342345", object);
}
}
结果:-----> success123456
使用泛型,有2个好处:
1.不需要做强制类型转换
2.编译时更安全。如果使用Object类的话,你没法保证返回的类型一定是Foo,也许是其它类型。这时你就会在运行时得到一个类型转换异常(ClassCastException)