本文主要介绍:编译器处理泛型方法和多态冲突的处理手段,桥方法
本文适合对象:想进一步理解JAVA中泛型机制的进阶玩家
先看例子
在正式介绍桥方法之前,先通过一个例子让大家对桥方法有点认知,不多说,上代码。
我们首先写一个普通的泛型类
public class MyGenerics<T> {
public void test(T t) {
System.out.println("in MyGenerics");
}
}
然后再写一个指定了具体泛型的该泛型类的子类
public class MyGenericsChild extends MyGenerics<String> {
public void test(String t) {
System.out.println("in MyGenericsChild");
}
}
最后是Main方法
public static void main(String[] args) {
MyGenerics<String> father = new MyGenericsChild();
father.test("hello");
}
( 不用在意这些玩具类的实际意义 )
问题是这个main方法运行的结果,我觉得我可以和你就这个结果打一个小赌。
这有什么好想的嘛,结果不肯定是:"in MyGenericsChild" ?
且慢,先听我分析一波再下决定:
- 编译过程中,泛型被擦除变成Object,MyGenerics类的test方法变成test(Object t)
- 子类的方法是 test(String t)
- JAVA中的多态是指参数不同而方法名相同的两个方法
- 调用的是父类.test,MyGenerics类没有test(String t)
如何,有没有一种被颠覆的感觉?没有?你要不再看一遍上面的四点?
按你的意思,结果会是:"in MyGenerics" 咯?
那决定好了?我们看一下运行结果:
in MyGenericsChild
诶先别急着拉黑,不觉得很奇怪吗,刚才那一波分析有理有据令人信服啊,怎么就出现这么一个奇葩的结果呢?
答案当然是因为这才是广大程序员想要的结果啊,咱JAVA这么优秀一个语言,肯定是考虑到了这个泛型方法和多态冲突的情况并且想出了处理方法。
好了废话不多说,标题上线预警。
正式介绍
为了解决这个冲突,JAVA在编译过程中,会自动生成一个桥方法(bridge method),它相当于以下代码:
public class MyGenericsChild extends MyGenerics<String> {
...
public void test(Object t) {
test((String) t);
}
...
}
这看起来似乎完美的解决了泛型方法和多态的冲突,但你有没有想过,如果是一个类似下面这段代码的,没有参数,仅有返回值的泛型方法,怎么办?
public class MyGenerics<T> {
private T data;
public T getData(){
return data;
};
}
那还不简单,生成这样的方法就可以了呗
public class MyGenericsChild extends MyGenerics<String> { public String getData() { return (String)super.getData(); } }
那问题又来了,在JAVA代码中,返回类型不同而参数类型相同的同名方法是不合法的
那怎么办?还有什么特殊的操作?
当然有了,虽然在JAVA代码中是不合法的,但是在虚拟机中合法啊 (滑稽)
在虚拟机中,用参数类型和返回类型来确定方法签名,因此,编译器可以产生两个仅返回类型不同的方法字节码,虚拟机能正确处理这种情况。
写在最后
好了,这篇文章是我第一篇针对性比较强的技术向博客,主要讲解了JAVA处理泛型和多态方法冲突的解决方案桥方法。虽然好像实际开发的时候并没有什么卵用……但是可以防踩坑啊!
网友评论