13.14. Inheritance and Polymorphism in Java: Liskov Substitution Principle
Object-oriented programming (OOP) is a programming paradigm that uses "objects" to model data and behavior. Java, being an object-oriented language, allows programmers to leverage concepts like inheritance and polymorphism to create more flexible and reusable programs. Let's deepen our understanding of these concepts and explore the Liskov Substitution Principle (LSP), one of the fundamental principles of object-oriented programming.
Inheritance in Java
Inheritance is a mechanism by which a new class, called a subclass, can inherit fields and methods from another class, called a superclass. This allows subclasses to reuse and extend the behavior of superclasses. In Java, inheritance is performed with the extends
keyword.
class Vehicle {
public void move() {
System.out.println("Vehicle in motion");
}
}
class Car extends Vehicle {
@Override
public void move() {
System.out.println("Car moving");
}
}
In the example above, Car
is a subclass of Vehicle
. The Car
subclass inherits the move()
method and provides its own implementation using the @Override
annotation. This illustrates the extension and reuse of functionality.
Polymorphism in Java
Polymorphism is the ability of an object to be treated as an instance of its own class or any class from which it inherits. In Java, this is commonly accomplished through method overriding and method overloading.
With method overriding, a subclass can provide a specific implementation of a method that already exists in its superclass. Method overloading allows multiple methods to have the same name, but with different parameter lists.
Liskov Substitution Principle (LSP)
The Liskov Substitution Principle, formulated by Barbara Liskov in 1987, is a fundamental concept in object-oriented programming. LSP states that if S
is a subtype of T
, then objects of type T
in a program can be replaced by objects of type S
without changing the desirable properties of that program. In other words, a subclass must be replaceable by its superclass without causing errors.
To join LSP, a subclass must:
- Do not change the expected behavior of superclass methods.
- Do not violate the invariants and contracts established by the superclass.
- Ensure that subtypes can be used to replace base types without needing to know the difference between them.
Violating LSP can lead to bugs and unexpected behavior in a program. For example:
class Bird {
public void fly() {
System.out.println("Bird flying");
}
}
class Penguin extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("Penguins don't fly");
}
}
In the example above, Penguin
is a subclass of Passaro
, but it overrides the fly()
method to throw an exception, as penguins do not fly. This violates LSP because the behavior of the Bird
superclass is changed in a way that can cause errors if Penguin
objects are used in contexts that expect all birds to be able to fly .
How to Apply LSP in Java
To ensure that LSP is respected in Java, follow these guidelines:
- Avoid overriding methods in a way that changes expected behavior.
- Use the
@Override
annotation when overriding methods to ensure that you are actually modifying a superclass method. - When necessary, use composition instead of inheritance to share behaviors between classes that do not have a substitutability relationship.
- Respect the contracts established by the superclass, including preconditions, postconditions and invariants.
Adopting LSP helps maintain the integrity of object-oriented design, promoting the creation of more robust and maintainable systems.
Conclusion
Inheritance and polymorphism are powerful concepts in Java that, when used correctly, can increase code reuse and flexibility. The Liskov Substitution Principle is essential to using these concepts effectively, ensuring that subclasses can be used in place of their superclasses without causing unwanted side effects. When designing and implementing your Java classes, always keep LSP in mind to create more consistent code.reliable and easy to maintain.