2

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

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

These clearly show multiple methods with the same call signature.

  1. How does Java resolve the function call?
  2. Why are there multiple functions?

EDIT: Simplified the question by keeping only the relevant bit.

  • 1
    Are you sure those are methods of the same class? – user2357112 Jul 21 '16 at 04:56
  • It is the output from `javap` - so I presume that they are methods of the same class. If you have a look at `javap -public java.lang.StringBuilder` - it clearly indicates that they belong to the same class (unless there is some behaviour of `javap` that I am not aware of) – Saurabh Das Jul 21 '16 at 04:59
  • first read this (https://stackoverflow.com/help/how-to-ask) – bananas Jul 21 '16 at 05:00
  • 1
    Everyone posting that these methods are just overloaded, please look at the `javap` output more carefully. There are method pairs with the exact same parameters, such as `public java.time.LocalTime minus(java.time.temporal.TemporalAmount);` and `public java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);`. That's not just overloading; overloading doesn't permit that. – user2357112 Jul 21 '16 at 05:02
  • Thank you - that is precisely what I am confused by. This case shouldn't be permitted by the overloading rules since there's no way to resolve the function from the list of parameters. I was unable to find anything on the web related to it either - this is an interesting edge case that would be instructive to know about. – Saurabh Das Jul 21 '16 at 05:06
  • There is no edge case. One is a class, and one is an interface. The class implements the interface. The class *must* have the same signature as the interface. – Makoto Jul 21 '16 at 05:07
  • 1
    `java.time.LocalTime` only has `public java.time.LocalTime minus(java.time.temporal.TemporalAmount);`. The other one might be a synthesized bridge method or similar. Did you look at the disassembly? – Andreas Fester Jul 21 '16 at 05:15
  • 1
    In order to clarify the question, I'd suggest removing the part about `StringBuilder`, which seems to be making people think you're asking about method overloading – Krease Jul 21 '16 at 05:23
  • They are not in the same class.... that is why is valid... – ΦXocę 웃 Пepeúpa ツ Jul 21 '16 at 05:24
  • @ΦXocę웃Пepeúpa They are. Not in the source, but in the class file. See the answer from user2357112 – Andreas Fester Jul 21 '16 at 05:34
  • I'd suggest using a more specific `grep` that gets rid of the distracting overloads and prunes the output down to two methods with the same signature. – user2357112 Jul 21 '16 at 05:38
  • Yes. In hindsight you are correct - should have kept the specific output only. – Saurabh Das Jul 21 '16 at 05:55

3 Answers3

7

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.

Source: http://www.artima.com/weblogs/viewpost.jsp?thread=354443

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 java.io.IOException;
    Code:
       0: aload_0       
       1: aload_1       
       2: invokevirtual #6                  // Method append:(Ljava/lang/CharSequence;)Ljava/lang/StringBuilder;
       5: areturn       
user2357112
  • 260,549
  • 28
  • 431
  • 505
2

Java forbids two methods in the same class or interface with the same name and signature.

However, two different classes, interfaces, or enums can have the same method signature; for example, this is valid:

public java.time.LocalTime minus(long, java.time.temporal.TemporalUnit);
public java.time.temporal.Temporal minus(long, java.time.temporal.TemporalUnit);

One minus method belongs to the LocalTime class, and the other belongs to the Temporal interface. Since LocalTime implements Temporal, there must be a signature match between those two or the contract is not fulfilled, which would lead to a compilation error.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • You're looking at the wrong pair of methods. Look at `public java.time.LocalTime minus(java.time.temporal.TemporalAmount);` and `public java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);`, for example. – user2357112 Jul 21 '16 at 05:00
  • 2
    @user2357112: Then there's no problem at all. Those are two different classes. – Makoto Jul 21 '16 at 05:01
  • Possibly, but then why are they both showing up in the `javap` output for `java.time.LocalTime`? – user2357112 Jul 21 '16 at 05:04
  • @user2357112: Why wouldn't they? `Temporal` defines its methods as part of its contract and `LocalTime` honors that contract, although that relationship isn't immediately apparent from the output of `javap` (hence one would want to consult the API). – Makoto Jul 21 '16 at 05:05
  • 1
    I didn't understand - how are they 2 different classes? They're 2 methods within the same class with the same name and the same argument list with different return values. As per the overloading rules, the return value is not part of the call signature and therefore these 2 methods aren't permitted to co-exist. – Saurabh Das Jul 21 '16 at 05:09
  • 1
    @SaurabhDas: `Temporal` isn't the same name as `LocalTime`. [The API makes this relationship apparent.](https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html) – Makoto Jul 21 '16 at 05:10
0

Temporal is interface which is implemented by LocalTime so their methods have same signature if you want to check try this

javap java.time.LocalTime

bananas
  • 1,176
  • 2
  • 19
  • 39