0

I was reading Thinking in Java, about why inner classes exist and what problem they help solve.

The most compelling reason the book tries to give is:

Each inner class can independently inherit from an implementation. Thus, the inner class is not limited by whether the outer class is already inheriting from an implementation.

Please help review my understanding:

Inner classes exist since Java doesn't support Multiple Inheritance. This (multiple inheritances) can be done within an Inner class which it is that the Outer class can have multiple inner classes, and each of them can inherit from different classes. So in this way, The multiple inheritances can be implemented. Another reason I can think of is Inner classes address the OOP design principle composition better than inheritance.

Updated

Most of the explanation I found just like the answers below. for example, Inner class used in the GUI framework to deal with the event handler. Not mentioned the reason quoted in the book.I am not saying the answers below are not the good. Actually. I really appreciated them(+1). I just want to know Is there something problem with the book?

Community
  • 1
  • 1
Joe.wang
  • 11,537
  • 25
  • 103
  • 180

3 Answers3

2

Why Use Nested Classes?

Compelling reasons for using nested classes include the following:

  • It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.
  • It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.
  • It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.

Oracle Documentation: Understanding inner classes

Below SO question might be interesting to you -

What is the reason for making a nested class static in HashMap or LinkedList?

UPDATE

Not mentioned the reason quoted in the book. ... I just want to know Is there something problem with the book?

I don't think there is any problem with the statement you have highlighted.

Each inner class can independently inherit from an implementation: That's true right. Just like an outer class, it can inherit from an implementation independently. Just think both of them as separate class.

Thus, the inner class is not limited by whether the outer class is already inheriting from an implementation: As both are separate class, it doesn't matter whether outer class is already inheriting from an implementation. Inner class can inherit from an implementation too. After all it's a class too.

Community
  • 1
  • 1
Kartic
  • 2,935
  • 5
  • 22
  • 43
2

It is a little puzzling why you thought of the idea of multiple inheritance after reading the most compelling reason you have quoted from the book. Multiple inheritance comes into question when a class (inner or not) wants to inherit behavior from more than one concrete implementation. Thus, unlike some other languages, in Java, you can not define a class like:

class Child extends Father, Mother {
   // Child wants to inherit some behavior from Father and some from Mother
}

As you can see, nothing that only inner classes do can rectify or work around this Java decision (not to support multiple inheritance) in a straightforward way.

Then why do they exist, you may wonder! Well, in Java every class is either top-level or inner (also called nested). Any class that is defined inside another class is an inner class and any class that isn't so is a top-level class.

Naturally, one might wonder why to define classes (i.e. behavior) inside other classes. Aren't top-level classes enough?

The answer is yes. Java could always have only top-level classes. But the idea (perhaps) was there was no good reason to restrict classes from being members of other classes! Just like any predefined type (e.g. Integer, String etc.) can be a member of a class:

class Person {
  private String name; // a field the models a Person's name
}

a programmer should be able to define a behavior of one's interest inside the class:

class Person {
  private String name; // a field the models a Person's name
  private Address address; // address is a type defined here
  static class Address {
    String street; 
    String city;
  }
}

There's a lot going on here, especially with these things like private, static etc. which are called the modifiers. There are many technical details about them, but let us come back to them later. The essential idea is to be able to define behavior as a part of another class. Could the Address class be defined outside Person class, as a top-level class? Of course. But having this facility comes in handy.

Now, since this facility was introduced, it started serving another purpose and that purpose is called providing code as data. This is how design patterns emerge and it was thought until about 10 years ago that inner classes can be used to provide the data in the form of code. Perhaps this is somewhat puzzling to you. Consider the following code that I have taken almost verbatim from the JDK class: java.lang.String.java:

public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                     = new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
        implements Comparator<String> {

    public int compare(String s1, String s2) {
        int n1 = s1.length();
        int n2 = s2.length();
        // details excluded for brevity
        // return -1, 0, 1 appropriately
    }
}

What has happened here?

We need a way to compare a String to another String and we need to be able to do a case-insensitive comparison. So, we created an implementation of the Comparator interface right inside the outer class: String! Isn't this handy? If inner class wouldn't be there, this would have to be:

public class String {
  // ... the whole String class implementation

}
class CaseInsensitiveComparator
            implements Comparator<String> {
   // implements the comparator method
}

and that's not 'bad' per se, but it means a lot of classes polluting the name space. Inner classes restrict the scope of a behavior to the outer class. That comes in handy, as you'd perhaps see. The data in this case is the implementation of the Comparator interface and the code is well, the same, because we are _new_ing up the inner class we defined.

This feature was exploited further using the anonymous inner classes (especially in the cases where you wanted the code to serve as data) up until Java 7 and they were effectively replaced by Lambda Expressions in Java 8. Nowadays, you might not see any new code that uses anonymous inner classes (in other words, language evolves).

Kedar Mhaswade
  • 4,535
  • 2
  • 25
  • 34
1

If you are looking for use-cases, I can only tell you what I use them for frequently, which are basically these 2 things:

  1. Static inner classes I use for helping to implement some internal logic. These are usually some form of tuples, or some simple containers. For example: Maps have "Entries" in them which are basically just pairs.

  2. Representing runtime parent-child relationships. These are non-static inner classes. For example: I have a Job class which may instantiate multiple Task inner classes that need to see the data in the job for their processing.

There may be more use-cases of course...

Robert Bräutigam
  • 7,514
  • 1
  • 20
  • 38