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:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | 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:
1 2 3 4 5 6 7 8 | 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?
1 2 3 4 5 6 7 8 9 | 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.
Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: The Subs Bench Opinions expressed by Java Code Geeks contributors are their own. |