The Subs Bench

a.k.a. “How do I subclass a list element declared in my interface?”

As covered by the rather awesome Ram on Baeldung, the Liskov substitution principle is important and is enforced by Java.

In a current project, we’re looking at our strong types having both interfaces and concrete implementations. There’s a reason for this that’s NOT about making things mockable. (Making everything an interface for mocking is overmocking.)

What’s nice and obvious is that this is possible:

public interface Bar {

}

public interface Foo {
    Bar getBar();
}

public class BarImpl implements Bar {
}

public class FooImpl implements Foo {
    public BarImpl getBar() { ... }
}

Despite the fact that the FooImpl subclass returns a subclass of the interface’s declared getter everything compiles happily, because a subclass can be substituted for a base class and still meet the Liskov substitution principle.

However, there’s a problem if you try to do this:

public interface Foo {
   List<Bar> getBars();
}

public class FooImpl implements Foo {
   // compiler error...
   public List<BarImpl> getBars() { ... }
}

In the Java generic type system, List<BarImpl> is not a subclass of List<Bar>. The folks who designed this stuff are pretty clever, and there’s probably a very good technical reason why this is the case.

The question is – can it be solved?

public interface Foo<T extends Bar> {
    // we know this is "at least" a Bar
    List<T> getBars();
}

public class FooImpl implements Foo<BarImpl> {
    // compiles great
    public List<BarImpl> getBars() { ... }
}

For lots of List or Optional of things, this might seem a bit cumbersome, but it is how it’s done… apparently.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s