An simple interface:
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
}
}
}
The output would be:
myMethod java.lang.String,
...//Other Method
Only one myMethod is printed.
But if I change the interface to a generic one:
interface Foo<T> {
void myMethod(T arg);
}
class FooImpl implements Foo<String> {
void myMethod(String arg){}
}
Then strangely the output will be:
myMethod java.lang.Object,
myMethod java.lang.String,
...//Other Method
Why after changing the interface to a generic one will lead to one more Method with a parameter type Object?
The first method is a bridge method, created by the compiler. If you test your methods for 'isBridge()', you can filter out the 'wrong' methods (also filters out some strange results you can get with covariance returns).
Following code will not print the 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);
}
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
}
UPDATE: Bridge methods
Quoting the blog:
Bridge methods in Java are synthetic methods, which are necessary to implement some of Java language features. The best known samples are covariant return type and a case in generics when erasure of base method's arguments differs from the actual method being invoked.
UPDATE CODE FROM above blog:
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;
}
}
}
On compiling the code will look like:
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
}
the bridge method, which overrides method from base class "A", not just calling one with string argument (#3), but also performs type cast to "java.lang.String" (#2). It means, that if you will execute following code, ignoring compiler's "unchecked" warning, the result will be ClassCastException thrown from the bridge method:
A a = new B();
a.getT(new Object()));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With