DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • A Guide to Constructor Chaining in Java
  • Achieving Inheritance in NoSQL Databases With Java Using Eclipse JNoSQL
  • Using Python Libraries in Java
  • Designing a Java Connector for Software Integrations

Trending

  • How to Format Articles for DZone
  • Ensuring Configuration Consistency Across Global Data Centers
  • Understanding Java Signals
  • Scalable, Resilient Data Orchestration: The Power of Intelligent Systems
  1. DZone
  2. Coding
  3. Java
  4. Problems With Inheritance in Java

Problems With Inheritance in Java

Having trouble with proper subclass inheritance in Java? Click here to figure out how to avoid broken code.

By 
Yogen Rai user avatar
Yogen Rai
·
Jul. 10, 18 · Tutorial
Likes (12)
Comment
Save
Tweet
Share
35.0K Views

Join the DZone community and get the full member experience.

Join For Free

Inheritance is one of the fundamental principles in an object-oriented paradigm, bringing a lot of values in software design and implementation. However, there are situations where even the correct use of inheritance breaks the implementations. This post is about looking at them closely with examples.

Fragility of Inheritance

The improper design of the parent class can leads subclasses of a superclass to use the superclass in unexpected ways. This often leads to broken code, even when the IS-A criterion is met. This architectural problem is known as the fragile base class problem in object-oriented programming systems.

The obvious reason for this problem is that the developer of a base class has no idea of the subclass design. When they modify the base class, the subclass implementation could potentially break.

For example, the following program shows how seemingly an inheriting subclass can malfunction by returning the wrong value.

class Rectangle {
    private int length;
    private int breadth;

    public Rectangle(int length, int breadth) {
        this.length = length;
        this.breadth = breadth;
    }

    public int calculateArea() {
        return length * breadth;
    }

    // getters and setters
}

// Square IS-A Rectangle
class Square extends Rectangle {
    public Square(int side) {
        super(side, side);
    }
}


Now, the following shows how to the test to ensure that the inheritance works fine. 

@Test
public void testSquare() {    
  Square square = new Square(5);    
  assertEquals("Area of square", 25, square.calculateArea());   // fine

  // set breadth of square :(    
  square.setBreadth(9);    
  assertEquals("Area of new square", 81, square.calculateArea());  // ohh nooo
}


Obviously, if I create the instance of Square  and call a method calculateArea, it will give the correct value. But, if I set any of dimension of the square, since the square is a rectangle, it gives the unexpected value for the area and the second assertion fails as below:

java.lang.AssertionError: Area of new square 
Expected :81
Actual :45


Is There Any Solution?

There is no straightforward solution to this problem because this is all about following the best practices while designing architecture. According to Joshua Bloch, in his book Effective Java, programmers should "design and document for inheritance or else prohibit it."

If there is a breakable superclass, it is better to prohibit inheritance by labeling a declaration of a class or method, respectively, with the keyword "final." And, if you are allowing your class to be extended, it is best to only use one way to populate fields.

Here, use either constructors  or setters  but not both.

So, if I remove the setters from the parent class as below:

class Rectangle {
    private int length;
    private int breadth;

    public Rectangle(int length, int breadth) {
        this.length = length;
        this.breadth = breadth;
    }

    public int calculateArea() {
        return length * breadth;
    }

    // getters
}


Then, the child classes can't misuse the setter avoiding fragility issue as:

@Test
public void testSquare() {    
  Square square = new Square(5);    
  assertEquals("Area of square", 25, square.calculateArea());   // fine

  // square.setBreadth(9);    //no way to set breadth :)
}


Inheritance Violates Encapsulation

Sometimes, your private data gets modified and violates encapsulation. This will happen if you are extending features from an undocumented parent class — even though the IS-A criterion is met.

For example, let us suppose A overrides all methods in B by first validating input arguments in each method (for security reasons). If a new method is added to B and A  and is not updated, the new method introduces a security hole.

For example, I have created new HashSet implementation to count the numbers of elements added to it as:

class MyHashSet<T> extends HashSet<T> {
    //The number of attempted element insertions since its creation --
    //this value will not be modified when elements are removed
    private int addCount = 0;

    public MyHashSet() {}

    @Override
    public boolean add(T a) {
        addCount++;
        return super.add(a);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        addCount += c.size();
        return super.addAll(c);
    }

    public int getAddCount() {
        return addCount;
    }
}


Everything looks good. So, it is time to test this extension!

@Test
public void testMyHashSet() {    
  MyHashSet<String> mhs = new MyHashSet<>();    
  mhs.add("A");    
  mhs.add("B");    
  mhs.add("C");    
  assertEquals("Number of attempted adds so far", 3, mhs.getAddCount());

  mhs.remove("B");    
  assertEquals("Number of attempted adds so far even after removal", 3, mhs.getAddCount());  

  mhs.addAll(Arrays.asList("D", "E", "F"));    
  assertEquals("Size of Elements in current set", 5, mhs.size());    
  assertEquals("New number of attempted adds so far", 6,  mhs.getAddCount());  // fails
}


The test fails with a failure in the last assertion as below:

java.lang.AssertionError: New number of attempted adds so far 
Expected :6
Actual :9
Inheritance


The cause of the problem is that in the implementation of  HashSet, addAll  calls the add  method. Therefore, we are incrementing  addCount  too many times in calls to  addAll. 

How to Fix This Issue?

The principle is the same as in an earlier fix: "Design and document for inheritance or else prohibit it." The proper documentation while designing features would reduce the chances of issues like this. 

Fix specific to this issue is not to increment  addCount  in  addAll  operations, since the value is getting updated in add  operation, which gets called from  addAll  as:

class MyHashSet<T> extends HashSet<T> {
    // . . .
    @Override
    public boolean addAll(Collection<? extends T> c) {
        return super.addAll(c);
    }
    // . . .
}


So, this is it! Until next time, happy learning!

As usual, all the source code presented in the above examples is available on GitHub.

Inheritance (object-oriented programming) Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • A Guide to Constructor Chaining in Java
  • Achieving Inheritance in NoSQL Databases With Java Using Eclipse JNoSQL
  • Using Python Libraries in Java
  • Designing a Java Connector for Software Integrations

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!