What's wrong with overridable method calls in constructors?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
In object-oriented programming, particularly in Java and C#, constructors often play a critical role in setting up new objects before they can be used. One common pitfall in the design of these classes can occur when constructors call overridable methods. Overridable methods are those not marked as final in Java or not sealed in C#. Calling such methods from within a constructor can lead to issues that disrupt the reliability and maintainability of software.
Understanding the Problem
When a constructor calls an overridable method, it exposes the partially constructed object to subclassed methods. This situation is problematic, as the subclass method can access or modify the object’s state which might not yet be fully initialized.
The primary issue arises because of the order in which constructors and initializers execute:
- The base class constructor runs before the subclass’s, which means that when the base class constructor invokes an overridable method, it runs the overridden version in the subclass.
- If the overridden method in the subclass depends on its own constructor having run, or on initialization that happens in the subclass constructor, it will be operating on incomplete data. This can lead to subtle bugs, and unexpected behavior, as the method might manipulate properties that are yet uninitialized.
Example to Illustrate the Issue
Consider a simple example in Java:
In this example, when DerivedClass is instantiated, the following happens:
DerivedClassconstructor calls theBaseClassconstructor.BaseClassconstructor callsinitialize().- The call to
initialize()is polymorphic and thus invokesinitialize()inDerivedClass. - Within
DerivedClass.initialize(), it attempts to accessmessage, which has not yet been initialized, leading to a NullPointerException.
Why is this a Problem?
Scalability - As systems grow, subclasses can multiply and evolve. Each new subclass introduces a potential failure point whenever overridable methods are called in constructors.
Maintainability - Troubleshooting and debugging issues related to incorrect initialization due to overridable method calls can be complex and time-consuming.
Security - In critical applications, partially initialized objects can lead to security holes, especially if the uninitialized state can be exploited.
Best Practices
Final and Sealed Methods - If using languages like Java or C#, enforce non-overridability by marking methods as final in Java or sealed in C#. This prevents them from being overridden.
Constructor Safe Methods - Only call private or final methods from constructors.
Initialization Blocks - Use separate initialization blocks or methods called explicitly after the constructor has completed all initializations.
Conclusion
Calling overridable methods from constructors can compromise the integrity and security of your application. It is best to adopt practices which ensure that objects are fully and safely initialized before they are used. Here’s a quick reference table summarizing the key insights:
| Aspect | Consideration |
| Scalability | Managing more subclasses increases the risk of improper initialization. |
| Security | Partially constructed objects can pose a security risk. |
| Best Practice | Use final or sealed to prevent methods from being overridden. |
| Alternative | Employ initialization blocks for setting up class-specific configurations safely. |
Understanding and avoiding the pitfalls of overridable method calls in constructors will lead to more reliable and robust object-oriented software.
Related reading
- What's wrong with using to compare floats in Java?
- When and how should I use a ThreadLocal variable?
- When and how should I use a ThreadLocal variable?
- When and why do we need ApplicationRunner and Runner interface?
- When and why JPA entities should implement the Serializable interface?
- When do I need to use AtomicBoolean in Java?
- When do Java generics require ? extends T instead of T and is there any downside of switching?
- When do you use Java's @Override annotation and why?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.