When is really useful to use a nested Java class?

2020-04-19 06:48发布

问题:

Could you give me a concrete example where a nested java class is useful? I am studying it, I understand how it works but I can not imagine a real situation where its use is really necessary.

Thank you so much

Marco

回答1:

The most concise summary of when to use a nested class is: when that class is logically part of the outer class' API, or when it encapsulates behavior specific to the outer class.

For example, Map.Entry: it's an entry in a mapping. It's logically part of Map's API, so it makes sense to put it inside Map.

Another common example is Builder classes: you use a Builder to make a thing, so it makes sense to put it inside that thing.

These are classes that you only really use in the context of using the outer classes: sometimes you might use a Map.Entry by itself as some sort of pair class; and sometimes you might want to use a Builder by itself, for example as a parameter to a method which puts things into that builder, but doesn't actually do the building itself. These cases are probably rarely far from code that also uses the outer class too: you're still using some aspect the outer class' API, so they do still logically belong to that API.

You could put such classes at the top level, alongside the "main" class. There are a few reasons why you might not want to do this:

  • It clutters the namespace. If you've got classes Foo, Bar, Baz etc, having FooBuilder, BarBuilder, BazBuilder at the top level just makes it harder to see the "useful" top level classes.
    • Google's protocol buffers generate a Builder class for every message type. Given the number of protocol buffers used in Google code, this clutter would be far too cumbersome.
  • Nested classes have access to private fields of the outer class, which may help you do certain things without unnecessarily exposing those fields.
  • You can refer to nested classes by qualifying the outer name, e.g. Outer.Builder, rather than having to explicitly import some.pkg.OuterBuilder as well as import some.pkg.Outer. Admittedly, I don't really care about the number of imports, since I just keep them collapsed in intellij.

You can also use them to encapsulate internal logic or intermediate state in the class: for example, I like to define private nested classes when I find myself passing around the same N parameters between private methods in a class. This is stuff that you don't want people outside your class to care about; it's merely convenient inside the class.



回答2:

It's used (also) to implement the Builder Pattern

First of all you need to create a static nested class and then copy all the arguments from the outer class to the Builder class



回答3:

I found them useful when I have classes that are part of one another evolving together. For instance, if I have base abstract classes:

abstract class Unit {
  private int HP;
  ....
  abstract class AI {
    abstract void heal();
  }
}

Later on, I can specify which type of unit I'm designing:

class Infantry extends Unit {
  ...
  class InfantryAI extends AI {
    void heal() { this->HP++; }
  }
}

What you see there is a secondary this - non-static nested classes (aka inner classes like AI and InfantryAI) can access their surrounding classes' (Unit and Infantry) private attributes as their own, and that access right propagates down the inheritance tree.

As for them being necessary - none of these OOP constructs are really necessary, but if it makes sense to you during design phase (like I thought it might be logical that AI is part of every Unit type so that it can control even it's private members), then you can use them.



回答4:

Nested classes are a way to organizing your code, one could say, sort of tight Encapsulation. While nested classes are not applicable to all situations, they are particularly useful when handling events.

The scope of a nested class is bounded by the scope of its enclosing class. So, if class B is defined within class A, then B does not exist independently of A. A nested class has access. to the members, including private members, of the class in which it is nested. However, the enclosing class does not have access to the members of the nested class. A nested class that is declared directly within its enclosing class scope is a member of its enclosing class.

The most used is the inner class. An inner class is a non-static nested class. It has access to all of the variables and methods of its outer class and may refer to them directly in the same way that other non-static members of the outer class do.

Finally there are anonymous inner classes, which are inner classes that don’t have a name.