Saurabh Das Saurabh Das - 1 year ago 43
Java Question

Java class has 2 methods with the same function signature but different return types

AFAIK it's not possible to have a method with the same call signature. However:

$ javap -public java.time.LocalTime | grep "minus" | grep "Temporal"
public java.time.LocalTime minus(java.time.temporal.TemporalAmount);
public java.time.LocalTime minus(long, java.time.temporal.TemporalUnit);
public java.time.temporal.Temporal minus(long, java.time.temporal.TemporalUnit);
public java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);

$ javap -public java.lang.StringBuilder | grep "append"
public java.lang.StringBuilder append(java.lang.Object);
public java.lang.StringBuilder append(java.lang.String);
public java.lang.StringBuilder append(java.lang.StringBuffer);
public java.lang.StringBuilder append(java.lang.CharSequence);
public java.lang.StringBuilder append(java.lang.CharSequence, int, int);
public java.lang.StringBuilder append(char[]);
public java.lang.StringBuilder append(char[], int, int);
public java.lang.StringBuilder append(boolean);
public java.lang.StringBuilder append(char);
public java.lang.StringBuilder append(int);
public java.lang.StringBuilder append(long);
public java.lang.StringBuilder append(float);
public java.lang.StringBuilder append(double);
public java.lang.StringBuilder appendCodePoint(int);
public java.lang.AbstractStringBuilder appendCodePoint(int);
public java.lang.AbstractStringBuilder append(double);
public java.lang.AbstractStringBuilder append(float);
public java.lang.AbstractStringBuilder append(long);
public java.lang.AbstractStringBuilder append(int);
public java.lang.AbstractStringBuilder append(char);
public java.lang.AbstractStringBuilder append(boolean);
public java.lang.AbstractStringBuilder append(char[], int, int);
public java.lang.AbstractStringBuilder append(char[]);
public java.lang.AbstractStringBuilder append(java.lang.CharSequence, int, int);
public java.lang.AbstractStringBuilder append(java.lang.CharSequence);
public java.lang.AbstractStringBuilder append(java.lang.StringBuffer);
public java.lang.AbstractStringBuilder append(java.lang.String);
public java.lang.AbstractStringBuilder append(java.lang.Object);
public java.lang.Appendable append(char) throws;
public java.lang.Appendable append(java.lang.CharSequence, int, int) throws;
public java.lang.Appendable append(java.lang.CharSequence) throws;

These clearly show multiple methods with the same call signature. Example: minus(java.time.temporal.TemporalAmount) with return type hava.time.LocalTime and java.time.temporal.Temporal.

  1. How does Java resolve the function call?

  2. Why are there multiple functions?

EDIT: Please examine the question correctly. I am aware of what overloading is. I'm pointing out that there are 2 methods with the same signature. ie: That have the same set of arguments. For example:
public java.time.LocalTime minus(java.time.temporal.TemporalAmount);
public java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);

Answer Source

This is due to how Java implements covariant return types. java.time.LocalTime has a minus method with signature

LocalTime minus(TemporalAmount amountToSubtract)

but this method implements an interface method from java.time.temporal.Temporal with signature

Temporal minus(TemporalAmount amount)

This is permitted due to covariant return typing, but due to the way method lookup works, a lookup at runtime for the method that returns a Temporal won't find the method that returns a LocalTime. Thus, the compiler creates an ordinarily-forbidden method with the same signature, but returning a Temporal. This method calls the version that returns a LocalTime. At runtime, calls that want a Temporal return type find the bridge method, and everything works out.

This bridge method is normally invisible, but it shows up in the javap output, leading to your current confusion.


Here's the javap -c disassembly for one of the bridge methods from StringBuilder, showing how it calls the method with the same signature, but a more specific return type:

  public java.lang.Appendable append(java.lang.CharSequence) throws;
       0: aload_0       
       1: aload_1       
       2: invokevirtual #6                  // Method append:(Ljava/lang/CharSequence;)Ljava/lang/StringBuilder;
       5: areturn