一个简单的界面:
interface Foo {
void myMethod(String arg);
}
class FooImpl implements Foo {
void myMethod(String arg){}
public static void main(String[] args) {
Class cls = FooImpl.class;
try {
for (Method method : cls.getMethods()) {
System.out.print(method.getName() + "\t");
for(Class paramCls : method.getParameterTypes()){
System.out.print(paramCls.getName() + ",");
}
System.out.println();
}
} catch (SecurityException e) {
// TODO Auto-generated catch block
}
}
}
输出结果为:
myMethod java.lang.String,
...//Other Method
只打印一个myMethod。
但是,如果我将界面更改为通用界面:
interface Foo<T> {
void myMethod(T arg);
}
class FooImpl implements Foo<String> {
void myMethod(String arg){}
}
然后奇怪的是输出将是:
myMethod java.lang.Object,
myMethod java.lang.String,
...//Other Method
为什么在将接口更改为通用接口后,将导致另一个具有参数类型Object的方法?
答案 0 :(得分:6)
第一种方法是由编译器创建的bridge method。 如果您测试&#39; isBridge()&#39;的方法,则可以过滤掉错误的&#39;方法(也过滤掉协方差返回时可能得到的一些奇怪的结果)。
以下代码不会打印myMethod java.lang.Object
:
import java.lang.reflect.Method;
public class FooImpl implements Foo<String> {
public void myMethod(String arg) {
}
public static void main(String[] args) throws Exception {
Class cls = FooImpl.class;
for (Method method : cls.getMethods()) {
if (!method.isBridge()) {
System.out.print(method.getName() + "\t");
for (Class paramCls : method.getParameterTypes()) {
System.out.print(paramCls.getName() + ",");
}
}
System.out.println();
}
}
}
interface Foo<T> {
public void myMethod(T arg);
}
答案 1 :(得分:2)
try {
for (Method method : cls.getMethods()) {
//these methods are called bridge methods
if(!method.isBridge()){
System.out.print(method.getName() + "\t");
for(Class paramCls : method.getParameterTypes()){
System.out.print(paramCls.getName() + ",");
}
System.out.println();
}
}
} catch (SecurityException e) {
// TODO Auto-generated catch block
}
更新: Bridge methods
引用博客:
Java中的桥接方法是必需的合成方法 实现一些Java语言功能。最着名的样本是 协变返回类型和基础擦除时的泛型案例 方法的参数与调用的实际方法不同。
更新代码来自博客:
public class SampleTwo {
public static class A<T> {
public T getT(T args) {
return args;
}
}
public static class B extends A<String> {
public String getT(String args) {
return args;
}
}
}
编译代码时将如下所示:
public SampleThree$B();
...
public java.lang.String getT(java.lang.String);
Code:
0: aload_1
1: areturn
public java.lang.Object getT(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #2; //class java/lang/String
5: invokevirtual #3; //Method getT:(Ljava/lang/String;)Ljava/lang/String;
8: areturn
}
桥接方法,它从基类“A”覆盖方法,而不是 只是用字符串参数(#3)调用一个,但也执行类型 强制转换为“java.lang.String”(#2)。这意味着,如果你将执行 下面的代码,忽略编译器的“未选中”警告,结果 将是从bridge方法抛出的ClassCastException:
A a = new B();
a.getT(new Object()));