Suppose I have this two interfaces...
public interface ObjectInterface { /* empty interface */ }
public interface ObjectHandler
{
void handle(ObjectInterface object);
}
...and also a concrete class which implements the ObjectInterface:
public class ConcreteObject implements ObjectInterface { /* ... */ }
Why is this not allowed in Java?
public class ConcreteHandler implements ObjectHandler
{
@Override
public void handle(ConcreteObject object) // <-- ObjectInterface implementation
{
// ...
}
}
A ConcreteObject implements the ObjectInterface interface afterall.
However, is there a way to design my classes in Java keeping this pattern of abstraction?
3 Answers 3
You can parameterize ObjectHandler with the class of accepted ObjectInterfaces:
public interface ObjectHandler<T extends ObjectInterface>
{
void handle(T object);
}
and use it as follows:
public class ConcreteHandler implements ObjectHandler<ConcreteObject>
{
@Override
public void handle(ConcreteObject object) // <-- now this works
{
// ...
}
}
1 Comment
javac compiler generates a method void handle(ObjectInterface oi) { handle((ConcreteObject) oi); } as a synthetic method for you +1Interface method is the contract,
void handle(ObjectInterface object);
Therefore the implementation of the interface should adhere to the contract. So it won't let you limit the object type it accepts.
handle(ConcreteObject object){...}
Above limits the input to the method, as its just a one implementation of ObjectInterface. Think what happens if there's another implementation called, ConcreteObject2 which implements the ObjectInterface. According to your code handle method won't accepts the ConcreteObject2 type objects.
If you want to keep the pattern you can use java generics
Comments
Because you're breaking the contract of the interface, and thus breaking the Liskov substitutioon principle.
The interface says: handle() can take any instance of ObjectInterface as argument. That's the contract: any implementation of handle() must accept any instance of ObjectInterface.
But the class says: handle() only accepts instances of ConcreteHandler.
ConcreteHandler#handlesince it only acceptsConcreteObjectand not the broader typeObjectInterface. So it fails to correctly implement theObjectHandlerinterface.