13.6 Inheritance and Polymorphism in Java: Constructors and Inheritance
Inheritance is one of the pillars of Object Oriented Programming (OOP) and allows a class to inherit characteristics from another class. In Java, inheritance is implemented with the extends
keyword. Polymorphism, on the other hand, is the ability of a method to have several forms, that is, the same method can behave differently depending on the context in which it is called. Both concepts are fundamental to creating flexible and reusable applications.
Builders and Inheritance
When we talk about constructors in an inheritance context, it is important to understand how the constructors of the base class (superclass) are affected by the derived class (subclass). In Java, the first task of any subclass constructor is to call a superclass constructor. If we don't do this explicitly, the compiler will try to call the default (argumentless) constructor of the superclass. If the superclass does not have a default constructor, we will have to explicitly call an existing constructor using the super
keyword.
public class Superclass {
public Superclass() {
// Default constructor
}
public Superclass(int arg) {
// Constructor with arguments
}
}
public class Subclass extends Superclass {
public Subclass() {
super(); // Call the Superclass's default constructor
}
public Subclass(int arg) {
super(arg); // Call the constructor with arguments from the Superclass
}
}
Note that if you do not explicitly call the superclass constructor using super()
, the compiler will do it for you, as long as a default constructor is available. If the superclass does not have a default constructor and the programmer does not explicitly call another constructor, the compiler will issue an error.
Inheritance and Encapsulation
Inheritance should also be used with caution in relation to encapsulation. If a base class has private fields, these are not directly accessible by the subclass. The subclass can access these fields only through public or protected methods (with the protected
keyword) of the base class. This is important to maintain data integrity and base class abstraction.
Polymorphism
Polymorphism in Java is mainly achieved through the override method. When a subclass provides a specific implementation for a method that already exists in the superclass, we say that the method has been overridden. This allows a superclass type reference to point to an object of the subclass type and the correct version of the method to be called, depending on the object's type.
public class Animal {
public void emitSound() {
System.out.println("The animal makes a sound");
}
}
public class Dog extends Animal {
@Override
public void emitSound() {
System.out.println("The dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog();
myAnimal.emitSound(); // Output: The dog barks
}
}
In this example, even if the reference myAnimal
is of type Animal
, the method emitSound()
that is called is that of the class < code>Dog, as the real object is a Dog
. This is a demonstration of polymorphism in action.
Final Considerations
Inheritance and polymorphism are fundamental to code reuse and building systems that are easy to maintain and expand. However, these concepts must be used with discernment. Inheritance can lead to complicated and difficult to understand class hierarchies if not planned well. Polymorphism, although powerful, can make code more difficult to follow because the exact behavior of the code may not be clear at first glance.
It is important to remember that inheritance should only be applied when an "is a" relationship makes sense. Using inheritance to reuse code may be tempting, but it can lead to an inappropriate class structure. Composition, that is, using objects from other classes as fields, is often a better alternative to inheritance.
In summary, inheritance and polymorphism are powerful tools in a Java programmer's toolbox, but like all tools, they must be used correctly to achieve the best results. Understanding how constructors interact with inheritance is an important step toward mastering these concepts and creating robust, flexible applications.