2

I'm trying to define and then implement an abstract setter which takes a List of Objects as a parameter. Here's the gist of this simple idea:

public abstract class MyClass {
    public abstract void setThings(List<?> things);
}

public class Bar extends MyClass {
    private List<String> things;

    @Override
    public void setThings(List<String> things) {
        this.things = things;
    }
}

That doesn't work. I get Method does not override method from its superclass and both methods have the same erasure, but neither overrides the other. I understand the latter error relating to erasures, but even so I can't figure out the correct way to do this. I've tried some others like:

public abstract <T> void setThings(List<T> things);

...as well as a few others. And I've found other questions/answers on SO that come close to addressing this, but none that have provided a solid answer (at least not that was clear to me). I've read through the tutorials as well to no avail. What am I missing?

Madbreaks
  • 19,094
  • 7
  • 58
  • 72

2 Answers2

4

So Java is quite correctly telling you that you haven't implemented the abstract method setThings which takes a List<?> not a List<T> or List<String>. All of these are different things. See this question for a detailed explanation.

The simplest solution is to introduce a generic for your abstract class as well:

public abstract class MyClass<T> {
    public abstract void setThings(List<T> things);
}

public class SubClass extends MyClass<String> {
    private List<String> things;

    public void setThings(List<String> things) {
        this.things = things;
    }
}
Community
  • 1
  • 1
sprinter
  • 27,148
  • 6
  • 47
  • 78
  • Thanks, I went with your example and it's working nicely. I'll have to spend some more time studying generics, some of the subtleties are still a bit mysterious to me such as the difference between using `?`, `T`, `E', etc. Nothing a little (more) reading can't remedy! – Madbreaks Oct 18 '16 at 15:53
2

List<?> things is a list of unknown type.

List<T> things is a list of type T.

These two things aren't the same, which is why you're getting that compilation error.

There are a couple of sensible ways to eradicate the error:

  • Generify both classes

    abstract class MyClass<T> {
        public abstract void setThings(List<T> things);
    }
    
    class Bar<T> extends MyClass<T> {
        private List<T> things;
    
        @Override
        public void setThings(List<T> things) {
            this.things = things;
        }
    }
    
  • Make Bar accept a list of unknown type as well

    abstract class MyClass {
        public abstract void setThings(List<?> things);
    }
    
    class Bar extends MyClass {
        private List<?> things;
    
        @Override
        public void setThings(List<?> things) {
            this.things = things;
        }
    }
    
Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Oops, I just forgot the `abstract` class modifier in my example but I do have that in my actual code. I've updated the question to reflect this. However I need a concrete type in my subclass. – Madbreaks Oct 18 '16 at 15:50