Implementing a generic Java interface adds an extra method

I have a generic Id<T> java interface with a single T getId() method and a MyClass class that implements Id<Long> . When I test methods declared on MyClass using java reflection, I see two methods: one with a return type of Long and one with a return type of Object . Where did the second method come from and how to 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); }; } 
+5
source share
3 answers

The second method is the synthetic bridge method, you can check it with method.isSynthetic() or method.isBridge() . You cannot delete it, but if you do not want to see it in the list of declared methods, just make sure that all these methods have isBridge() == false .

Synthetic bridge methods are automatically added to universal classes at compile time. 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 
+3
source

This is a function. The same question was raised in

JDK-8060179 Class.getDeclaredMethods () returns inconsistent results using generics and closes as "no error".

+2
source

You can find the compiled methods with 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 other return type is Object (it calls the Long getId method).

method It is intended for processing when the general type and Long getId bridge are not specified. Example:

  Id<Long> id = new Id<Long>() { @Override public Long getId() { return null; } }; Long id1 = id.getId(); 

as the code snippet above, we can implement the anonymous class Id with type Long . but we can also implement the anonymous class Id without specifying a generic type in the variable:

  Id id = new Id<Long>() { @Override public Long getId() { return null; } }; Object id1 = id.getId(); 

therefore, at the moment, the compiler cannot deduce a common type for the Id variable when id.getId() returns an Object type, which means that it calls this method public java.lang.Object getId(); and bridge to public java.lang.Long getId(); .

+1
source

Source: https://habr.com/ru/post/1269224/


All Articles