Inheritance

What is it?

Object-oriented programming allows classes to inherit commonly used state and behaviour from other classes.

Inheritance is the mechanism by which a new class is derived from an existing class, inheriting all of its properties and methods.

Inheritance allows new classes (subclasses or derived classes) to inherit properties and behaviors from existing classes (superclasses or base classes).

It promotes code reuse, reduces redundancy, and establishes a hierarchical relationship between classes.

For example, a Dog class and a Cat class can inherit from a Mammal class, inheriting properties like number of legs and warm-blooded and methods like eat(), makeNoise(), sleep(), etc. Since Dog and Cat have some common features and methods, the common functionality can be written in the base class or the parent class. In addition to inheriting common fields and methods, the Dog class can add its own specific characteristics like barking(), swimming(), etc. Similarly, the Cat class can add it’s own methods like meows(). It is enough to implement the behavior that is specific to the child classes in Dog and Cat classes.

Types of Inheritance are:

  1. Single inheritance
  2. Multi-level inheritance
  3. Multiple inheritances
  4. Hybrid inheritance
  5. Hierarchical inheritance

Benefits

https://www.cs.princeton.edu/courses/archive/fall98/cs441/mainus/node12.html

There are two benefits of inheritance: subtyping and subclassing

  1. Subtyping means conforming to a type (interface) signature, i.e. a set of APIs, and one can override part of the signature to achieve subtyping polymorphism.
  2. Subclassing means implicit reuse of method implementations.

With the two benefits comes two different purposes for doing inheritance: subtyping oriented and code reuse oriented.

Disadvantages of Inheritance

With all the undeniable benefits provided by inheritance, here’s some of its disadvantages.

  1. You can’t change the implementation inherited from super classes at runtime (obviously, because inheritance is defined at compile time).
  2. Inheritance exposes a subclass to details of its parent class implementation. That is why, it is often said that inheritance breaks encapsulation (in a sense that you really need to focus on interfaces only not implementation, so reusing by sub classing is not always preferred).
  3. The tight coupling provided by inheritance makes the implementation of a subclass very bound up with the implementation of a super class that any change in the parent implementation will force the sub class to change.
  4. Excessive reusing by sub-classing can make the inheritance stack very deep and very confusing too.

A much more complete and concrete answer from Tim Boudreau of Sun:

Common problems to the use of inheritance as I see it are:

  1. Innocent acts can have unexpected results - The classic example of this is calls to overridable methods from the superclass constructor, before the subclasses instance fields have been initialized. In a perfect world, nobody would ever do that. This is not a perfect world.
  2. It offers perverse temptations for subclassers to make assumptions about order of method calls and such - such assumptions tend not to be stable if the superclass may evolve over time. See also my toaster and coffee pot analogy.
  3. Classes get heavier - you don’t necessarily know what work your superclass is doing in its constructor, or how much memory it’s going to use. So constructing some innocent would-be lightweight object can be far more expensive than you think, and this may change over time if the superclass evolves
  4. It encourages an explosion of subclasses. Classloading costs time, more classes costs memory. This may be a non-issue until you’re dealing with an app on the scale of NetBeans, but there, we had real issues with, for example, menus being slow because the first display of a menu triggered massive class loading. We fixed this by moving to more declarative syntax and other techniques, but that cost time to fix as well.
  5. It makes it harder to change things later - if you’ve made a class public, swapping the superclass is going to break subclasses - it’s a choice which, once you’ve made the code public, you’re married to. So if you’re not altering the real functionality to your superclass, you get much more freedom to change things later if you use, rather than extend the thing you need. Take, for example, subclassing JPanel - this is usually wrong; and if the subclass is public somewhere, you never get a chance to revisit that decision. If it’s accessed as JComponent getThePanel() , you can still do it (hint: expose models for the components within as your API).
  6. Object hierarchies don't scale (or making them scale later is much harder than planning ahead) - this is the classic too many layers problem. I’ll go into this below, and how the AskTheOracle pattern can solve it (though it may offend OOP purists).

My take on what to do, if you do allow for inheritance, which you may take with a grain of salt is:

  1. Expose no fields, ever, except constants
  2. Methods shall be either abstract or final
  3. Call no methods from the superclass constructor

all of this applies less to small projects than large ones, and less to private classes than public ones

Reading material

  1. https://en.wikipedia.org/wiki/Fragile_base_class

Tags

  1. Inheritance - Diamond problem
  2. Interfaces and Abstract classes