2

I understand that Java does not have multiple inheritance.

I'm reading Effective Java 3rd Edition Item 20 (page 102), here is a portion from the page:

The beauty of skeletal implementation classes is that they provide all of the implementation assistance of abstract classes without imposing the severe constraints that abstract classes impose when they serve as type definitions. For most implementors of an interface with a skeletal implementation class, extending this class is the obvious choice, but it is strictly optional. If a class cannot be made to extend the skeletal implementation, the class can always implement the interface directly. The class still benefits from any default methods present on the interface itself. Furthermore, the skeletal implementation can still aid the implementor’s task. The class implementing the interface can forward invocations of interface methods to a contained instance of a private inner class that extends the skeletal implementation. This technique, known as simulated multiple inheritance, is closely related to the wrapper class idiom discussed in Item 18. It provides many of the benefits of multiple inheritance, while avoiding the pitfalls.

Since English is not my native language, the bold part of the quote got me confused. And I got no result when search for the answer.

What is this private inner class? Is this like a normal inner class?

In practice, does this technique get use very often?

Any code example would be extremely useful for me to visualize!

Thank you!

ABC
  • 145
  • 2
  • 7
  • Take a look [here](https://stackoverflow.com/questions/13436995/why-and-when-to-use-skeletal-implementation-in-java). It may not answer your question, but is useful I guess. – Zakk Mar 19 '22 at 19:19
  • @Zakk Thank you. But I already read it before I ask the question. Unfortunately, without an example, I still cannot visualize it correctly. – ABC Mar 19 '22 at 19:23
  • _"Is this like a normal inner class?"_ Yes, it is. I don't know if [this](https://stackoverflow.com/a/6264730/16835308) answers your question. – Zakk Mar 19 '22 at 19:45
  • @Zakk Thank you. I think I found the answer from [this useful article](https://10kloc.wordpress.com/2012/12/03/abstract-interfaces-the-mystery-revealed/). It has a nice example but never mentions **simulated multiple inheritance** but I guess that's acceptable. – ABC Mar 19 '22 at 19:57
  • So, please answer your own question and mark it as the accepted one. This way, others can benefit from it. – Zakk Mar 19 '22 at 20:00

2 Answers2

1

What is this private inner class?

An example:

class OuterClass {
    private class InnerClass {
        {
            
        }
    }
}
StepUp
  • 36,391
  • 15
  • 88
  • 148
  • I understand the `private inner class` now but my main question is about `simulated multiple inheritance`. Any concrete code example? Thanks! – ABC Mar 22 '22 at 20:36
0

Suppose we have an interface called Shape that represents geometric shapes with methods for calculating area and perimeter.

We will create a skeletal implementation class AbstractShape that provides default implementations for these methods, and then we will have a class Circle that directly implements the Shape interface but also reuses code from AbstractShape by forwarding method calls to an inner class.

// Interface representing a geometric shape
interface Shape {
    double getArea();
    double getPerimeter();
}

// Skeletal implementation class providing default implementations
abstract class AbstractShape implements Shape {
    // Common method implementations for all shapes
    @Override
    public double getArea() {
        return 0.0;
    }

    @Override
    public double getPerimeter() {
        return 0.0;
    }
}

// Class representing a Circle, which directly implements Shape
class Circle implements Shape {
    private final double radius;

    // Constructor for Circle
    public Circle(double radius) {
        this.radius = radius;
    }

    // Inner class that extends the skeletal implementation
    private class CircleImpl extends AbstractShape {
        @Override
        public double getArea() {
            return Math.PI * radius * radius;
        }

        @Override
        public double getPerimeter() {
            return 2 * Math.PI * radius;
        }
    }

    // Forward method calls to the inner CircleImpl instance
    private final CircleImpl circleImpl = new CircleImpl();

    @Override
    public double getArea() {
        return circleImpl.getArea();
    }

    @Override
    public double getPerimeter() {
        return circleImpl.getPerimeter();
    }
}

public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle(5.0);
        System.out.println("Circle Area: " + circle.getArea());
        System.out.println("Circle Perimeter: " + circle.getPerimeter());
    }
}

In this example, AbstractShape serves as a skeletal implementation of the Shape interface, providing default implementations for getArea() and getPerimeter(). The Circle class directly implements the Shape interface, but it also has an inner class CircleImpl, which extends AbstractShape and provides specific implementations for getArea() and getPerimeter() tailored to circles.

By forwarding the method calls to the inner CircleImpl instance, the Circle class is effectively reusing the code from AbstractShape without having to extend it directly.

This allows the Circle class to benefit from the implementation assistance provided by the skeletal implementation, while still being free to implement other interfaces or extend different classes as needed.

This is what is referred to as simulated multiple inheritance in Java and as you can see it's way more flexible than using only polymorphism and inheritance.

metronic
  • 455
  • 5
  • 15