I have a generic java interface Id<T>
with a single method T getId()
and a class MyClass
that implements Id<Long>
. When I inspect the methods declared on MyClass
using java reflection, I see two methods: one with return type Long
, and one with return type Object
. Where does the second method come from and how can I remove it?
Here is the source:
package mypackage;
import java.lang.reflect.Method;
public class MainClass {
public static void main(String[] args) {
for (Method method : MyClass.class.getDeclaredMethods()) {
System.out.println(method);
}
// prints out two lines
// public java.lang.Long mypackage.MyClass.getId() <-- ok
// public java.lang.Object mypackage.MyClass.getId() <-- not ok
}
}
interface Id<T> {
T getId();
}
class MyClass implements Id<Long> {
@Override
public Long getId() {
return new Long(0);
};
}
The second method is a synthetic bridge
method, you can check it with method.isSynthetic()
or method.isBridge()
. You can't remove it, but if you don't want to see it in the list of declared methods, just check all those methods to have isBridge() == false
.
Synthetic bridge methods are added automatically to generic classes during compilation. You can read more about synthetic methods here.
for (Method method : MyClass.class.getDeclaredMethods()) {
System.out.println("Method: " + method);
System.out.println("synthetic: " + method.isSynthetic());
System.out.println("bridge: " + method.isBridge());
}
// 1
//Method: public java.lang.Long Main$MyClass.getId()
//synthetic: false
//bridge: false
// 2
//Method: public java.lang.Object Main$MyClass.getId()
//synthetic: true
//bridge: true
This is feature. Same issue was raised in
JDK-8060179 Class.getDeclaredMethods() returning inconsistent results with generics and closed as 'not a bug'.
You can find the compiled methods by javap -c MyClass
:
Compiled from "Test.java"
class MyClass implements Id<java.lang.Long> {
MyClass();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.Long getId();
Code:
0: new #2 // class java/lang/Long
3: dup
4: lconst_0
5: invokespecial #3 // Method java/lang/Long."<init>":(J)V
8: areturn
public java.lang.Object getId();
Code:
0: aload_0
1: invokevirtual #4 // Method getId:()Ljava/lang/Long;
4: areturn
}
As you can see there are 2 methods for getId
, one return type is Long
as implementation
and the another return type is Object
type (it's invoking the Long getId
method).
The return type Object
method is for handling when no specify the generic type and bridge to Long getId
method. Example:
Id<Long> id = new Id<Long>() {
@Override
public Long getId() {
return null;
}
};
Long id1 = id.getId();
as the above code snippet we can implement the Id
anonymous class with the Long
type. but the problem we also can implement the Id
anonymous class like without specify generic type in variable:
Id id = new Id<Long>() {
@Override
public Long getId() {
return null;
}
};
Object id1 = id.getId();
so for now the compiler can't infer generic type for variable id
, when id.getId()
it's returning type Object
type variable, it means it's calling this method public java.lang.Object getId();
and bridge to public java.lang.Long getId();
method.
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