8

I'm using generics in Java for the first time, and I'm facing an issue I don't manage to overcome: why this compiles:

public interface Aa{}
public interface Bb{}
public interface Cc{}


public static <GenericAB extends Aa & Bb>
void method(GenericAB myABobject1, GenericAB myABobject2){}

public static <GenericAB extends Aa & Bb, GenericCA extends Cc & Aa>
void method(GenericAB myAbobject, GenericCA myCAobject){}

But this does not:

public interface Aa{}
public interface Bb{}
public interface Cc{}


public static <GenericAB extends Aa & Bb>
void method(GenericAB myABobject1, GenericAB myABobject2){}

public static <GenericAB extends Aa & Bb, GenericAC extends Aa & Cc>
void method(GenericAB myAbobject, GenericAC myACobject){}

And I get this error: both methods have same erasure.

I'm sorry if this is a stupid question, but I don't get why the order of interfaces in a bounded type parameter declaration seems to have importance. In reality I don't think it is the order which causes the error, but I don't get what does.

I'm reading this documentation by Oracle, it says which I must put the class as first parameter but Aa, Bb and Cc are all interfaces. Sorry for my english too.

Lapo
  • 592
  • 1
  • 7
  • 22

2 Answers2

4

It is the order that matters (§4.6):

The erasure of a type variable (§4.4) is the erasure of its leftmost bound.

GenericBC erases to either Aa or Cc, depending on which appears first (i.e. leftmost) in the bound.

Also see type erasure tutorial and type erasure, when and what happens Q&A for explanations of type erasure in general.

Radiodef
  • 35,285
  • 14
  • 78
  • 114
  • Thanks for the answer! Isn't this limitating? Or at least confusing? I mean, if I want to overload a function with generics (as I did in my question's example) why do I have to pay attention to the order? Moreover, doesn't this mechanism risks to limitate the number of overloaded methods based on the number of interfaces I want to bound (I don't manage to come to an example tho)? I mean, if Oracle did this way of course there is a good reason, but I don't get what. By the way tomorrow I'll read the links you posted for sure, I tried to read them quickly but they seem a bit complicated. Thanks! – Lapo May 29 '18 at 18:59
  • In general, we can't do overloads with generics because of the "no two methods with same erasure" rule. I'm going to guess that the reason it's not allowed has to do with backwards compatibility (old pre-generics code using new post-generics code). I don't think there's any other limitation. I think there are some other JVM languages that do allow this kind of overloading. – Radiodef May 29 '18 at 19:49
  • Ok, I read the links and I'm starting understanding, even tho I still have some doubts, but I think that working with them is the best way to get used to them. By the way, when you say "we can't do overloads with generics[...]" do you mean that we should not or that it is impossible? I'm asking this because the above example works and there I'm overloading a method with generics. Thank you! – Lapo May 30 '18 at 19:38
  • 1
    It's prohibited to have two methods which have the same name and erasure. (See [§8.4.8.3](https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.8.3), under the 1st bold section that starts like "It is a compile-time error...".) For example, `void m(List l) {} void m(List l) {}` would be a compiler error because both methods erase to `void m(List l) {}`. The example in your question (where the type variables erase differently) is just a fairly obscure special case. – Radiodef May 30 '18 at 19:46
1

Because at runtime after type erasure both of the methods have the same method header

public static <GenericAB extends Aa & Bb> void method(GenericAB myABobject1, GenericAB myABobject2){}

becomes

public static void method(Aa myABobject1, Aa myABobject2){}

and

public static <GenericAB extends Aa & Bb, GenericBC extends Aa & Cc>void method(GenericAB myAbobject, GenericBC myBCobject){}

becomes

public static void method(Aa myAbobject, Aa myBCobject){}

both resulting methods have the same signature which results in your error

EDIT after comments below parameters are fixed

Michal
  • 907
  • 7
  • 10