This approach stems from the concept of abstraction, one of the key in the world of the PLO. In practice, this allows you to save the programmer who will use your code from the details of a specific implementation. Using interfaces allows you to use objects that implement the interface, regardless of what is under the hood. More specifically: there may be several objects that implement this interface, you can work with them completely equally within the framework of the implemented interface.
For example:
class Dog implements AbleToEat() { @Override public void eat() { sout("Dog is eating"); } } class Snake implements AbleToEat() { @Override public void eat() { sout("Mmmm rabit is tasty!"); } } class Test { ArrayList<AbleToEat> whoIsEat = new ArrayList<>(); whoIsEat.add(new Dog()); whoIsEat.add(new Snake()); for (AbleToEat something : whoIsEat) { something.eat(); } }
For a deeper understanding of the issue I advise you to read that abstraction in the PLO.