3

I have the following structure

public interface A <T extends B> {

  List<String> getVals();

  void setVals(List<String> vals);

  T getContext();

  void setContext(T context);
}

public abstract class C <T extends B> implements A {
   protected T context;

   //Some code
}

public class Regex <T extends B> extends C <T> {
   public List<String> getVals() {
     //Some code
   }

   public void setVals(List<String> vals) {
     //Some code
   }
}

The thing is that, when I compile, I'm getting the following error:

Regex.java:[53,15]
name clash: setVals(java.util.List<java.lang.String>) in Regex and setVals(java.util.List<java.lang.String>) in A have the same erasure, yet neither overrides the other

Why is this? If I ask Intellij to "do the overwrite" for me and it replaces the setVals(List vals) with setVals(List vals) instead.

   public void setVals(List vals) {
     //Some code
   }

It shouldn't be, "exactly the same definition of the method"?

Sorry in advance for my lack of interfaces knowledge

Fingolricks
  • 1,196
  • 2
  • 14
  • 30
  • 5
    Your `C` extends the raw type `A` which will lead to all kinds of problems. Did you mean `C` to extend `A` instead? – Joachim Sauer Dec 18 '19 at 15:16
  • 3
    in other words: it should have been `public abstract class C implements A` and not `implements A` – Jesper Dec 18 '19 at 15:19
  • You all mentioned the same and, ofc, it was the correct approach. Now it fixed. Amazing! – Fingolricks Dec 18 '19 at 17:31
  • 1
    Does this answer your question? [interface and a class. name clash: same erasure, yet neither overrides other](https://stackoverflow.com/questions/15442508/interface-and-a-class-name-clash-same-erasure-yet-neither-overrides-other) – Julien Lopez Dec 18 '19 at 17:40

1 Answers1

3

I am guessing you want to implement parameterized type but are actually implementing the raw one.

Replace

public abstract class C <T extends B> implements A

with

public abstract class C <T extends B> implements A<T>

An interesting observation to note here is, that the function setVals is not even using the type parameter T, even then there is a name clash. So it is not obvious at first why this is happening, and why simply extending, A<T> works. At least not to me.

The answer lies here,

The supertype of a class may be a raw type. Member accesses for the class are treated as normal, and member accesses for the supertype are treated as for raw types. In the constructor of the class, calls to super are treated as method calls on a raw type.

and

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

C in our case is also coincidentally C.

So without extending A<T> from Cs perspective the signature of A is,

void setVals(List vals)

and the compiler doesn't see void setVals(List<String> vals) in Regex as overriding that of A, instead it is considering it overloading, and that too an illegal overload because of type erasure. (You can't overload foo(List) with foo(List<String>)

Adwait Kumar
  • 1,552
  • 10
  • 25