《JAVA编程思想》学习备忘(p345 Inner Classes-3)

续《JAVA编程思想》学习备忘(p345 Inner Classes-2)

Closures & callbacks

A closure is a callable oject that retains information from the scope in which it was created.

The closure provided by the inner class is a good solution-more flexible and far safer than a pointer.Here's an example:

interface Incrementable {
 void increment();
}

class Callee1 implements Incrementable {
 private int i = 0;
 public void increment() {
  i++;
  System.out.println(i);
 }
}

class MyIncrement{
 public void increment(){
  System.out.println("Other operation");
 }
 static void f(MyIncrement mi){mi.increment();}
}

//If your class must implement increment() in
//some other way,you must use an inner class:
class Callee2 extends MyIncrement{
 private int i = 0;
 public void increment(){
  super.increment();
  i++;
  System.out.println(i);
 }
 private class Closure implements Incrementable{
  public void increment() {
   //Specify outer-class method,otherwise
   //you'd get an infinite recursion:
   Callee2.this.increment();
  }
 }
 Incrementable getCallbackReference(){
  return new Closure();
 }
}

class Caller{
 private Incrementable callbackReference;
 Caller(Incrementable cbh){callbackReference = cbh;}
 void go(){callbackReference.increment();}
}
public class Callbacks {
 public static void main(String[] args) {
  Callee1 c1 = new Callee1();
  Callee2 c2 = new Callee2();
  MyIncrement.f(c2);
  Caller caller1 = new Caller(c1);
  Caller caller2 = new Caller(c2.getCallbackReference());
  caller1.go();
  caller1.go();
  caller2.go();
  caller2.go();
 }
}

输出:

Other operation
1
1
2
Other operation
2
Other operation
3

The value of the callback is in its flexiblility;you can dynamically decide what methods will be called at run time.The benefit of this will become more evident in the Graphical User Interfaces chapter,where callbacks are used everywhere to implement GUI functionality.

 

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.

A control framework is a particular type of application framework dominated by the need to respond to events.

示例:

public abstract class Event {
 private long eventTime;
 protected final long delayTime=0;
 public Event(long delayTime){
  this.eventTime = delayTime;
  start();
 }
 public void start(){//Allows restarting
  eventTime = System.nanoTime() + delayTime;
 }
 public boolean ready(){
  return System.nanoTime() >= eventTime;
 }
 public abstract void action();
}

public class Controller {
 // A class from java.util to hold Event objects:
 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);
    }
 }
}

public class GreenhouseControls extends Controller {
 private boolean light = false;
 public class LightOn extends Event {
  public LightOn(long delayTime){super(delayTime);}
  public void action() {
   // Put hardware control code here to
   // physically turn on the light.
   light = true;
  }
  public String toString(){return "Light is on";}
 }
 public class LightOff extends Event{
  public LightOff(long delayTime){super(delayTime);}
  public void action() {
   // Put hardware control code here to
   // physically turn off the light.
   light = false;
  }
  public String toString(){return "Light is off";}
 }
 private boolean water = false;
 public class WaterOn extends Event{
  public WaterOn(long delayTime){super(delayTime);}
  public void action() {
   // Put hardware control code here.
   water = true;
  }
  public String toString(){return "Greenhouse water is on";}
 }
 public class WaterOff extends Event{
  public WaterOff(long delayTime){super(delayTime);}
  public void action(){
   // Put hardware control code here.
   water = false;
  }
  public String toString(){return "Greenhouse water is off";}
 }
 private String thermostat = "Day";
 public class ThermostatNight extends Event{
  public ThermostatNight(long delayTime){super(delayTime);}
  public void action(){
   // Put hardware control cod here.
   thermostat = "Night";
  }
  public String toString(){return "Thermostat on night setting";}
 }
 public class ThermostatDay extends Event{
  public ThermostatDay(long delayTime){super(delayTime);}
  public void action(){
   // Put hardware control code here.
   thermostat = "Day";
  }
  public String toString(){return "Thermostat on day setting";}
 }
 // An example of an action() that inserts a
 // new one of itself into the event list:
 public class Bell extends Event{
  public Bell(long delayTime){super(delayTime);}
  public void action(){
   addEvent(new Bell(delayTime));
  }
  public String toString(){return "Bing!";}
 }
 public class Restart extends Event{
  private Event[] eventList;
  public Restart(long delayTime,Event[] eventList){
   super(delayTime);
   this.eventList = eventList;
   for(Event e : eventList)
    addEvent(e);
  }
  public void action(){
   for(Event e : eventList){
    e.start(); // Rerun each event
    addEvent(e);
   }
   start(); // Rerun this Event
   addEvent(this);
  }
  public String toString(){return "Restarting system";}
 }
 public static class Terminate extends Event{
  public Terminate(long delayTime){super(delayTime);}
  public void action(){System.exit(0);}
  public String toString(){return "Terminating";}
 }
}
public class GreenhouseController {
 public static void main(String[] args) {
  GreenhouseControls gc = new GreenhouseControls();
  // Instead of hard-wiring, you could parse
  // configuration information from a text file here:
  gc.addEvent(gc.new Bell(900));
  Event[] eventList = {
    gc.new ThermostatNight(0),
    gc.new LightOn(200),
    gc.new LightOff(400),
    gc.new WaterOn(600),
    gc.new WaterOff(800),
    gc.new ThermostatDay(1400)
  };
  gc.addEvent(gc.new Restart(2000, eventList));
  if(args.length == 1)
   gc.addEvent(
    new GreenhouseControls.Terminate(
     new Integer(args[0])
    )
   );
  gc.run();
 }
}
从命令输入行输入参数5000运行程序后输出:

Bing!
Thermostat on night setting
Light is on
Light is off
Greenhouse water is on
Greenhouse water is off
Thermostat on day setting
Restarting system
Terminating

This example should move you toward an appreciation of the value of inner classes,especially when used within a control framework.

 

Inheriting from inner classes

use the syntax: enclosingClassReference.super();

示例:

class WithInner {
 class Inner{}
}

public class InheritInner extends WithInner.Inner {
 //! InheritInner(){} // Won't compile
 InheritInner(WithInner wi){
  wi.super();
 }
 public static void main(String[] args){
  WithInner wi = new WithInner();
  InheritInner ii = new InheritInner(wi);
 }
}

 

Can inner classes be overridden?

..."override" an inner class as if it were another method of the outer class doesn't really do anything:

class Egg {
 private Yolk y;
 protected class Yolk{
  public Yolk(){System.out.println("Egg.Yolk()");}
 }
 public Egg(){
  System.out.println("New Egg()");
  y = new Yolk();
 }
}

public class BigEgg extends Egg {
 public class Yolk{
  public Yolk(){System.out.println("BigEgg.Yolk()");}
 }
 public static void main(String[] args) {
  new BigEgg();
 }

}

输出:

New Egg()
Egg.Yolk()

示例:

class Egg2 {
 protected class Yolk{
  public Yolk(){System.out.println("Egg2.Yolk");}
  public void f(){System.out.println("Egg2.Yolk.f()");}
 }
 private Yolk y = new Yolk();
 public Egg2(){System.out.println("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(){System.out.println("BigEgg2.Yolk()");}
  public void f(){System.out.println("BigEgg2.Yolk.f()");}
 }
 public BigEgg2(){insertYolk(new Yolk());}
 public static void main(String[] args) {
  Egg2 e2 = new BigEgg2();
  e2.g();
 }
}
输出:

Egg2.Yolk
New Egg2()
Egg2.Yolk
BigEgg2.Yolk()
BigEgg2.Yolk.f()

Local inner classes

A local inner class cannot have an access 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.Here's an example comparing the creation of a local inner class with an anonymous inner class:

public interface Counter {
 int next();
}

public class LocalInnerClass {
 private int count = 0;
 Counter getCounter(final String name){
  // A local inner class:
  class LocalCounter implements Counter{
   public LocalCounter(){
    // Local inner class can have a constructor
    System.out.println("LocalCounter()");
   }
   public int next(){
    System.out.print(name); // Access local final
    return count++;
   }
  }
  return new LocalCounter();
 }
 // The same thing with an anonymous inner class:
 Counter getCounter2(final String name){
  return new Counter(){
   // Anonymous inner class cannot have a named
   // constructor, only an instance initializer:
   {
    System.out.println("Counter()");
   }
   public int next(){
    System.out.print(name); // Access local final
    return count++;
   }
  };
 }
 public static void main(String[] args) {
  LocalInnerClass lic = new LocalInnerClass();
  Counter
   c1 = lic.getCounter("Local inner"),
   c2 = lic.getCounter2("Anonymous inner");
  for(int i = 0; i < 5; i++)
   System.out.println(c1.next());
  for(int i = 0; i < 5; i++)
   System.out.println(c2.next());
 }
}
输出:

LocalCounter()
Counter()
Local inner0
Local inner1
Local inner2
Local inner3
Local inner4
Anonymous inner5
Anonymous inner6
Anonymous inner7
Anonymous inner8
Anonymous inner9

...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

the name of the enclosing class,followed by a '$',followed by the name of the inner class.For example,the .class files created by LocalInnerClass.java include:

Counter.class

LocalInnerClass$1.class

LocalInnerClass$1LocalCounter.class

LocalInnerClass.class

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值