0

My understanding about generic was that if I have public void saveAll(Collection<? extends Object> stuff) { then compile will determine the "most common type" of the input parameter to be Collection<Object>. Now, with that I wrote below code for overriding the generic methods, but I get following error message in the overriding method - Name clash: The method saveAll(Collection<? extends Object>) of type ChildWithGenericMethod has the same erasure as saveAll(Collection<Object>) of type ParentWithGenericMethod<T> but does not override it

public class ParentWithGenericMethod {
    public void saveAll(Collection<Object> stuff) {

    }
}

public class ChildWithGenericMethod extends ParentWithGenericMethod{
    public void saveAll(Collection<? extends Object> stuff) {

    }
}

What I want to know is that after type erasure how these methods would look like, I thought they would look like public void saveAll(Collection stuff) { and hence I should be able to override, because if I don't use generics then I can override like this.

Please note that I know that I can see the byte code after compilation using "javap" but it doesn't tell me how these methods would look like after "type erasure".


Update:
This question doesn't answer my question, if after type erasure both methods become public void saveAll(Collection stuff) { then why subclass is getting overriding error, because with public void saveAll(Collection<Object> stuff) { it passes the overriding rules.
pjj
  • 2,015
  • 1
  • 17
  • 42
  • 2
    "after type erasure how these methods would look like" `public void saveAll(Collection stuff)` – Andy Turner May 10 '17 at 19:37
  • 1
    What do you mean by "most common type"? – user2357112 May 10 '17 at 19:37
  • @AndyTurner Then why I am getting that error that it is not overriding the method? – pjj May 10 '17 at 19:40
  • @pjj because you're not overriding the method. To override, the parameters have to be exactly the same type. [JLS](https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.1). – Andy Turner May 10 '17 at 19:40
  • @user2357112 Suppose you have `public void saveAll(T t, List l) {` then compiler would determine the most common type as `Serializable` – pjj May 10 '17 at 19:40
  • 2
    @pjj: That's... not how generics work. I don't know where you got this idea. – user2357112 May 10 '17 at 19:41
  • Possible duplicate of [Java generics name clash , has the same erasure](http://stackoverflow.com/questions/11933931/java-generics-name-clash-has-the-same-erasure) – PM 77-1 May 10 '17 at 19:41
  • 2
    And why do you think the compiler would let a method override a method with an incompatible signature just because the erasures match? – user2357112 May 10 '17 at 19:42
  • 1
    @user2357112 That's how generics work, read here http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html the example with "Serializable" – pjj May 10 '17 at 19:48
  • @user2357112 How signatures are incompatible, I don't understand, after type erasure if both methods become `public void saveAll(Collection stuff)` then it passes the overriding rules, right? – pjj May 10 '17 at 19:50
  • 2
    See http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.1, "An instance method `mC` ... in ... class C, overrides ... another method mA ... in class A, iff all of the following are true: ,,, The signature of mC is a subsignature ,,, of the signature of mA.", and http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2, "Two methods ,,,, M and N, have the same signature if they have the same name, the same type parameters (if any), and, after adapting ,,, the type parameters ..., the same formal parameter types." Overriding is compile time, _before_ erasure. – Lew Bloch May 10 '17 at 19:50
  • 1
    @pjj, "That's how generics work" - no, it isn't. The tutorial example shows type inference (hence the section title, "Type Inference"), and there isn't the same level of information in your example as in the tutorial's. Please study further. I recommend Anglelika Langer's excellent site, http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html, and the Java Language Specification (JLS), and a number of excellent articles on the IBM Developerworks site. There's no type inference available for `Serializable` in your example. – Lew Bloch May 10 '17 at 19:54
  • 1
    @pjj: You've completely misunderstood that example. Among other things, it's using type inference *at the call site* to determine what `T` is for *that specific call*. It doesn't and cannot simply look at the method definition and decide that `T` is `Serializable`. – user2357112 May 10 '17 at 19:54
  • 1
    It doesn't override because `Collection extends Object>` is not the same type as `Collection`. Take, for example, an `ArrayList`. That array list is certainly a `Collection extends Object>` but it's _not_ a `Collection` because you can't go putting arbitrary objects into it. – Dawood ibn Kareem May 10 '17 at 19:56
  • @user2357112 See this type erasure example where `T` is replaced by `Comparable` after type erasure, because compiler determined the most common type to be "Comparable", and this is what I am assuming in my question as well. – pjj May 10 '17 at 20:00

2 Answers2

1

It's worth remembering run time vs compile-time dispatch.

Take away generics for a second.

public class Parent {
  public void saveAll(Object x) {
  }
}

public class Child extends Parent {
   public void saveAll(String x) {
  }
}

public String x = "hello";
public Object y = new Integer(334);
public Object z = "goodbye";

public Child c1 = new Child();

c1.saveAll(x); // invokes Child.saveAll
c1.saveAll(y); // invokes Parent.saveAll
c1.saveAll(z); // invokes Parent.saveAll even though z contains a String

Now put generics back into the story.

 public class Child<T extends Object> extends Parent {
   public void saveAll(T x) {
  }
}

Here, saveAll overloads, rather than overrides, the parent's saveAll.

replacing T with an anoymous ? doesn't really change that -- the compiler is trying to create a method that overloads the parent's method, but then realizes that it can't dispatch on compile-time type.

[edit, see Lew Block's comment on the original: the compiler needs to decide whether the child method overrides or overloads the parent's method before type erasure]

Chris Owens
  • 1,107
  • 1
  • 10
  • 15
0

if after type erasure both methods become public void saveAll(Collection stuff) { then why subclass is getting overriding error, because with public void saveAll(Collection stuff) { it passes the overriding rules.

The problem (again see Lew Bloch's comment) is that overriding is determined before type erasure. Before type erasure, the parent and child method have different signatures, and so the compiler creates them as overloaded methods rather than overriding methods. After type erasure, the compiler realizes it is in a bind because it now has two methods with the same signature and no way to know how to dispatch.

Chris Owens
  • 1,107
  • 1
  • 10
  • 15