您的位置:首页 > 编程语言 > Java开发

Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十)之Inner Classes

2016-01-12 12:10 609 查看
  The inner class is a valuable feature because it allows you to group classes that logically belong together and to control the visibility of one within the other. However, it's important to understand that inner classes are distinctly different from composition.

  The kind of code you can write with inner classes is more elegant and clear.

  More typically, an outer class will have a method that returns a reference to an inner class.

  If you want to make an object of the inner class anywhere except from within a non-static method of the outer class, you must specify the type of that object as OuterClassName.InnerClassName.

The linke to the outer class

  When you create an inner class, an object of the inner class has a link to the enclosing object that made it, and so it can access the members of the enclosing object. In addition, inner class have access rights to all the elements in the enclosing class.

  The inner class secretly captures a reference to the particular object of the enclosing class that was responsible for creating it. An object of an inner class can be created only in association with an objecct of the enclosing class (When ,as you shall see, the inner class is non-static).

Using .this and .new

  If you need to produce the reference to the outer-class object, you name the outer class followed by a dot and this.

  Sometimes you want to tell some other object to create an object of one of its inner classes. To do this you must provide a reference to the outer-class object in the new expression, using the .new syntax.

  DotNew dn = new DotNew();

  DotNew.Inner dni = dn.new Inner();

  It's not possible to create an object of the inner class unless you already have an object of the outer class. This is because the object of the inner class is quietly connected to the object of the outer class that it was made from. However, if make a nested class (a static inner class), then it doesn't need a reference to the outer-class object.

Inner classes and upcasting

  Inner class really come into their own (有了用武之地) when you start upcasting to a base cass, and in particular to an interface.

Inner classes in methods and scopes

  In general, the code that you'll write and read involving inner classes will be "plain" inner classes that are simple and easy to understand. However, the syntax for inner classes covers a number of other, more obscure techniques. Inner classes can be created within a method or even an arbitrary scope. Theare are two reasons for doing this:

  1. As shown previously, you're implementing an interface of some kind so that you can create and return a reference.

  2. You're solving a complicated problem and you want to create a class to aid in youre solution, but you don't want to publicly available.

  The class created within the scope of a method is called a local inner class.

  The fact that the class is placed inside a method doesn't mean that The object of the class is not a valid object once the method returns.

  The class is nested inside the scope of an if statement. This does not mean that the class is conditionally created--it gets compiled along with everything else. However, it's not available outside the scope in which it is defined. Other than that, it looks just like an ordinary class.

Anonymous inner classes

  public Contents contents() {

    return new Contents() { // Insert a class definition

      private int i = 11;

      public int value() { return i;}

    }; // Semicolon required in this case

  }

  What this strange syntax means is "Create an object of an anonymous class that's inherited from Contents." The reference returned by the new expression is automatically upcast to a Contents reference.

  The anonymous inner-class syntax is a shorthand for:

  class Mycontents implements Contents {

    private int i = 11;

    public int value() { return i;}

  }

  public Contents contents() {return new MyContents();}

  return new Wrapping(x) { // Pass constructor argument.

    public int value() {

      return super.value() * 47;

    }

  }; // Semicolon required

  

  public Destination destination (final String dest) {

    return new Destination() {

      private String label = dest; // initialization

      public String readLabel() {return label; }

    };

  }

  虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效。因为编译的时候内部类和方法在同一级别上,所以方法中的变量或参数只有为final,内部类才可以引用。

  You can't have a named constructor in an anonymous class (since there's no name!), but with instance initialization, you can, in effect, create a constructor for an anonymous inner class.

  return new Base(j) {

    { print("Inside instance initializer"); }

    public void f() {...};

  }

  It's limited; you can't overload instance initializers, so you can have only one of these constructors.

  Anonymous inner class are somewhat limited compared to regular inheritance, because they can either extend a class or implement an interface, but not both. And if you do implement an interface, you can only implement one.

  Factory Method revisited

  You often only need a single factory object, and so here it has been created as a static field in the Service implementation by annoymous inner class.

Nested classes

  A nested class means:

    1. You don't need an outer-class object in order to create an object of a nested class.

    2. You can't access a non-static outer-class object from an object of a nested class.

  Fields and methods in ordinary inner classes can only be at the outer level of a class, so ordinary inner classes cant have static data, static fields, or nested classes. Howover, nested classes can have all of these.

  A nested class does not have a special this reference, which makes it analogous to a static method.

  Classes inside interfaces

  Any class you put inside an interfae is automatically public and static.

  You can even implement the surrounding interface in the inner class.

  It's convenient to nest a class inside an interface when you want to create some common code to be used with all different implementations of that interface.

  Java TestBed$Tester

  Reaching outward from a multiply nested class

Why inner classes ?

  an inner class provides a kind of window into the outer class.

  A question that cuts to the heart of inner classes is this: If I just need a reference to an interface, why don't I just make the outer class implement that interface? The answer is that you can't always have the convenience of interfaces-sometimes you're working with implementations.

  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

  One way to look at the inner class is as the rest of the solution of the multiple-inheritance problem.

  If you didn't need to solve the "multiple implementation inheritance" problem, you could conceivably code around everything else without the need for inner classes. But with inner classes you have these additional features:

  1. The inner class can have multiple instances, each with its own state information that is independent of the information in the outer class object.

  2. In a single outer class you can have several inner classes, each of which implements the same interface or inherits from the same class in a different way.

  3. The point of creation of the inner-class object is not tied to the creation of the outer-class obect (??)

  4. There is no potentially confusing "is-a" relationship with the inner class; it's a separate entity.

  Closures & callbacks (闭包和回调)

  A closure is a callable object that retains information from the scope in which it was created. From this definition, you can see that an inner class is an object-oriented closure, because it doesn't just contain each piece of iinformation from the outer-class object ("the scope in which it was created"), but it automatically holds a reference back to the whole outer-class object, where it has permission to manipulate all the members, even private ones.

  With a callback, some other object is given a piece of information that allows it to call back into the originating object at some later point. But a callback is implemented using a pointer.

  The closure provided by the inner class is a good solution-more flexible and far safer than a pointer.

  Inner classes & control frameworks

  An application framework is a class or a set of classes that's designed to solve a particular type of problem.(应用框架的定义:用于解决某种类型问题的一个类或一组类)

  application framework is an example of the Template Method design pattern (模板方法设计模式)

  The Template Method contains the basic structure of the algorithm, and it calls one or more overrideable methods to complete the action of that algorithm.

  设计模式就是将变化的事物和保存不变的事物分离开。

  Template Method 就是保持不变的部分,而可覆盖的方法就是变化的部分

  A control framework is a particular type of application framework dominated by the need to response to events. (控制框架是一类特殊的应用程序框架,用来解决响应事件的需求)

  A system the primarily responds to events is called an event-driven system. (事件驱动系统)

  Java Swing library is a control framework

  

  public class Controller {

    private List<Event> eventList = new ArrayList<Event>();

    public void addEvent(Event c) { eventList.add(c); }

    public void run() {

      while(eventList.size() > 0)

        // Make a copy so you're not modifying the list

        // while you're selecting the elements in it:

        for (Event e : new ArrayList<Event>(eventList))

          if (e.ready()) {

            System.out.println(e);

            e.action(); // 变动部分

            eventList.remove(e);

          }

    }  

  }

  The is where inner class comme into play. They allow two things:

    1. The entire implementation of a control framework is created in a single class, thereby encapsulating everything that's unique about that implementation. Inner classes are used to express the many different kinds of action() necessary to solve the problem.

    2. Inner classes keep this implementation from becoming awkward, since you're able to easily access any of the members in the outer class. Without the ability the code might become unpleasant enough that you'd end up seeking an alternative.

Inheriting from inner classes

  Because the inner-class constructor must attach to a reference of the enclosing class object, things are slightly complicated when you inherit from an inner class. The problem is that the "secret" reference to the enclosing class object must be initialized, and yet in the derived class there’s no longer a default object to attach to. You must use a special syntax to make the association explicit

  class WithInner {

    class Inner {}

  }

  public class InheritInner extends WithInner.Inner {

    // ! InheritInner() {} // Won't compile

    InheritInner(WithInner wi) { //******

      wi.super();

    }

  }

Can inner classes be overridden ?

  class Egg {

    private Yolk y;

    protected class Yolk {

      public Yolk { print("Egg.Yolk)"); }

    }

    public Egg() {

      print("New Egg()");

      y = new Yolk();

    }

  }

  public class BigEgg extends Egg {

    public class Yolk {

      public Yolk { print("BigEgg.Yolk()"); }

    }

    public static void main(String[] args) {

      new BigEgg();

    }

  } /* Output:

  New Egg()

  Egg.Yolk()

  */

  The two inner classes are completely separate entities, each in its own namespace. However, it’s still possible to explicitly inherit from the inner class  

  class Egg2 {
    protected class Yolk {
      public Yolk() { print("Egg2.Yolk()"); }
      public void f() { print("Egg2.Yolk.f()");}
    }
    private Yolk y = new Yolk();
    public Egg2() { print("New Egg2()"); }
    public void insertYolk(Yolk yy) { y = yy; }
    public void g() { y.f(); }
  }
  public class BigEgg2 extends Egg2 {
    public class Yolk extends Egg2.Yolk {
      public Yolk() { print("BigEgg2.Yolk()"); }
      public void f() { print("BigEgg2.Yolk.f()"); }
    }
    public BigEgg2() { insertYolk(new Yolk()); }
    public static void main(String[] args) {
      Egg2 e2 = new BigEgg2();
      e2.g();
    }
  } /* Output:
  Egg2.Yolk()
  New Egg2()
  Egg2.Yolk()
  BigEgg2.Yolk()
  BigEgg2.Yolk.f()

  */

Local inner classes

  A local inner class canot have an acces specifier because it isn't part of the outer class, but it does have access to the final variables in the current code block and all the members of the enclosing class.

  Since the name of the local inner class is not accessible outside the method, the only justification for using a local inner class instead of an anonymous inner class is if you need a named constructor and/ or an overloaded constructor, since an anonymous inner class can only use instance initialization.

  Another reason to make a local inner class rather than an anonymous inner class is if you need to make more than one object of that class.

Inner-class identifiers

  If inner classes are anonymous, the compiler simply starts generating numbers as inner-class identifiers. If inner classes are nested within inner classes, their names are simply appended after a ‘$’ and the outer-class identifier (s).

Summary

  Interfaces and inner classes solve the same problem that C++ attempts to solve with its multiple inheritance (MI) feature.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: