开发者

Why we use inner classes?

I want to ask you why we need inner classes and wh开发者_运维技巧y we use them ?

I know how to use inner classes but I don't know why..


Some inner classes are exposed publicly (eg Map.Entry in Java) but that is by far the exception rather than the norm.

Inner classes are, basically, an implementation detail.

For example, Swing makes extensive use of inner classes for event listeners. Without them you would end up polluting the global namespace with a bunch of classes you otherwise don't need to see (which may make their purpose harder to determine).

Essentially inner classes are a form of scope. Package access hides classes from outside the package. Private inner classes hide that class from outside that class.

Inner classes in Java are also a substitute for a lack of function pointers or method delegates (which are in C#) or closures. They are the means of passing a function to another function. For example, in the Executor class you have:

void execute(Runnable r);

so you can pass a method in. In C/C++ that could be achieved with:

void execute(void (*run)());

being a pointer to a function.


This piece from wikipedia might help you understand why we need an inner class:

An instance of a normal or top-level class can exist on its own. By contrast, an instance of an inner class cannot be instantiated without being bound to a top-level class.

Let us take the abstract notion of a Car with four wheels. Our wheels have a specific feature that relies on being part of our Car. This notion does not represent the wheels as wheels in a more general form that could be part of vehicle. Instead it represents them as specific to this one. We can model this notion using inner classes as follows:

We have the top-level class Car. Instances of Class Car are composed of four instances of the class Wheel. This particular implementation of Wheel is specific to the car, so the code does not model the general notion of a Wheel which would be better represented as a top-level class. Therefore, it is semantically connected to the class Car and the code of Wheel is in some way coupled to its outer class.

Inner classes provide us with a mechanism to accurately model this connection. We say that our wheel class is Car.Wheel, Car being the top-level class and Wheel being the inner class.

Inner classes therefore allow for the object orientation of certain parts of the program that would otherwise not be encapsulated into a class.


Anonymous inner classes in Java are a way to use the adapter pattern.

interface Bar
{
  public void bar();
}

class Foo
{
  public void foo()
  {
    // do something relevant
  }

  // it happens that foo() defines the same contract (or a compatible one) as
  // Bar.bar(); with an anonymous inner class we can adapt Foo to the Bar
  // interface
  public Bar asBar()
  {
    // return an instance of an anonymous inner class that implements
    // the Bar inteface
    return new Bar()
    {
      public void bar()
      {
        // from an inner class, we can access the enclosing class methods
        // as the "this pointers" are "linked"
        foo();
      }
    };
  }
}

In Java, make sure you understand the difference between inner classs and nested class:

an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields

C# doesn't have inner classes in sense of Java, only nested classes.

See also this Inner Class Example.


Most of the time I use inner classes is because inner classes are the closest thing to the concept of closure available in other languages. This enables creating and working with an object of inner nested scope which has access to variables of its outer scope. This is often useful in creating callbacks (e.g. defining various Listeners in Swing) among other things.


I use them to scope, for example, if I have the class ebook and I have ebookPrice, I enclose ebookPrice between the ebook class, as it is related to it and only usable (at least conceptually) inside it.

ebookPrice may inherit from Price which is in a more higher scope, and related to every other class.

(Just my two cents).


There are languages that take inner classes to quite some different level, like Beta and Newspeak. In these languages the nesting of classes serves as packaging (ie there are no packages).

For a good coverage of this vision, please refer to "How many concepts for modules do we need?" on the object teams blog. See also the work by Gilad Bracha on his blog...


The object-oriented advantage

In my humble opinion, the most important feature of the inner class is that it allows you to turn things into objects that you normally wouldn't turn into objects. That allows your code to be even more object-oriented than it would be without inner classes.

Let's look at the member class. Since its instance is a member of its parent instance, it has access to every member and method in the parent. At first glance, this might not seem like much; we already have that sort of access from within a method in the parent class. However, the member class allows us to take logic out of the parent and objectify it. For example, a tree class may have a method and many helper methods that perform a search or walk of the tree. From an object-oriented point of view, the tree is a tree, not a search algorithm. However, you need intimate knowledge of the tree's data structures to accomplish a search.

An inner class allows us to remove that logic and place it into its own class. So from an object-oriented point of view, we've taken functionality out of where it doesn't belong and have put it into its own class. Through the use of an inner class, we have successfully decoupled the search algorithm from the tree. Now, to change the search algorithm, we can simply swap in a new class. I could go on, but that opens up our code to many of the advantages provided by object-oriented techniques.

The organizational advantage

Object-oriented design isn't everyone's thing, but luckily, inner classes provide more. From an organizational point of view, inner classes allow us to further organize our package structure through the use of namespaces. Instead of dumping everything in a flat package, classes can be further nested within classes. Explicitly, without inner classes, we were limited to the following hierarchy structure:

package1
   class 1
      class 2
      ...
      class n
...
package n

With inner classes we can do the following:

package 1
   class 1
   class 2
      class 1
      class 2
      ...
      class n

Used carefully, inner classes can provide a structural hierarchy that more naturally fits your classes.

The callback advantage

Inner member classes and anonymous classes both provide a convenient method for defining callbacks. The most obvious example relates to GUI code. However, the application of the callback can extend to many domains.

Most Java GUIs have some kind of component that instigates an actionPerformed() method call. Unfortunately, most developers simply have their main window implement ActionListener. As a result, all components share the same actionPerformed() method. To figure out which component performed the action, there is normally a giant, ugly switch in the actionPerformed() method.

Here's an example of a monolithic implementation:

public class SomeGUI extends JFrame implements ActionListener {

    protected JButton button1;
    protected JButton button2;
    //...
    protected JButton buttonN;

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button1) {
        // do something
        } else if (e.getSource() == button2) {
            //... you get the picture
        }
    }
}

Whenever you see switches or large if/if else blocks, loud alarm bells should begin to ring in your mind. In general, such constructs are bad object-oriented design since a change in one section of the code may require a corresponding change in the switch statement. Inner member classes and anonymous classes allow us to get away from the switched actionPerformed() method.

Instead, we can define an inner class that implements ActionListener for each component to which we want to listen. That may result in many inner classes. However, we can avoid large switch statements and have the added bonus of encapsulating our action logic. Moreover, that approach may improve performance. In a switch where there are n comparisons, we can expect n/2 comparisons in the average case. Inner classes allow us to set up a 1:1 correspondence between the action performer and the action listener. In a large GUI, such optimizations can make a substantial impact on performance. An anonymous approach may look like this:

public class SomeGUI extends JFrame {
    //  ... button member declarations ...

    protected void buildGUI() {
        button1 = new JButton();
        button2 = new JButton();
        //...
        button1.addActionListener(
                new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {
                // do something
            }
        });
// .. repeat for each button
    }
}

Using inner member classes, the same program would look like this:

public class SomeGUI extends JFrame
{
   ... button member declarations ...
   protected void buildGUI()
   {
      button1 = new JButton();
      button2 = new JButton();
      ...
      button1.addActionListener(
         new java.awt.event.ActionListener()
         {
            public void actionPerformed(java.awt.event.ActionEvent e)
            {
               // do something
            }
         }
      );
      .. repeat for each button

Since inner classes have access to everything in the parent, we can move any logic that would have appeared in a monolithic actionPerformed() implementation to an inner class.

I prefer to use member classes as callbacks. However, that is a matter of personal preference. I just feel that too many anonymous classes clutter code. I also feel that anonymous classes can become unwieldy if they are larger than one or two lines.

Disadvantages?

As with anything else, you have to take the good with the bad. Inner classes have their disadvantages. From a maintenance point of view, inexperienced Java developers may find the inner class difficult to understand. The use of inner classes will also increase the total number of classes in your code. Moreover, from a development point of view, most Java tools come up a bit short on their support of inner classes. For example, I use IBM's VisualAge for Java for my day-to-day coding. While inner classes will compile within VisualAge, there is no inner class browser or template. Instead, you must simply type the inner class directly into the class definition. That unfortunately makes browsing the inner class difficult. It is also difficult to type since you lose many of VisualAge's code completion aids when you type into the class definition or use an inner class

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜