zoukankan      html  css  js  c++  java
  • Thinking in Java from Chapter 10

    From Thinking in Java 4th Edition

    内部类

    public class Parcel1 {
    	class Contents {
    		private int i = 11;
    		public int value { return i;}
    	}
    	
    	class Destination {
    		private String label;
    		Destination(String whereTo) {
    			label = whereTo;
    		}
    		
    		String readLabel() { return label;}
    	}
    	
    	// Using inner classes looks just like
    	// using any other class, within Parcel1;
    	public void ship(String dest) {
    		Contents c = new Contents();
    		Destination d = new Destination(dest);
    		System.out.println(d.readLable());
    	}
    	
    	public static void main(String[] args) {
    		Parcel1 p = new Parcel1();
    		p.ship("Tasmania");
    	}
    } /* Output:
    Tasmania
    */
    

    更典型的情况是,外部类将有一个方法,该方法返回一个指向内部类的引用

    public class Parcel2 {
    	class Contents {
    		private int i = 11;
    		public int value() { return i;}
    	}
    	
    	class Destination {
    		private String label;
    		Destination(String whereTo) {
    			label = whereTo;
    		}
    		String readLabel() { return label;}
    	}
    	
    	public Destination to(String s) {
    		return new Destination(s);
    	}
    	
    	public Contents contents() {
    		return new Contents();
    	}
    	
    	public void ship(String dest) {
    		Contents c = contents();
    		Destination d = to(dest);
    		System.out.println(d.readLabel());
    	}
    	
    	public static void main(String[] args) {
    		Parcel2 p = new Parcel2();
    		p.ship("Tasmania");
    		Parcel2 q = new Parcel2();
    		
    		// Defining references to inner classes:
    		Parcel2.Contents c = q.contents();
    		Parcel2.Destination d = q.to("Borneo");
    	}
    } /* Output:
    Tasmania
    */
    

    当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了联系,它能访问其外围对象的所有成员。内部类拥有其外围类的所有元素的访问权:

    interface Selector {
    	boolean end();
    	Object current();
    	void next();
    }
    
    public class Sequence {
    	private Object[] items;
    	private int next = 0;
    	
    	public Sequence(int size) { item = new Object[size];}
    	
    	public void add(Object x){
    		if(next < items.length)
    			items[next++] = x;
    	}
    	
    	private class SequenceSelector implements Selector {
    		private int i = 0;
    		public boolean end() { return i == items.length; }
    		public Object current() { return items[i];}
    		public void next() { if(i < items.length) i++;}
    	}
    	
    	public Selector selector() {
    		return new SequenceSelector();
    	}
    	
    	public static void main(String[] args){
    		Sequence sequence = new Sequence(10);
    		for(int i = 0; i < 10; ++i)
    			sequence.add(Integer.toString(i));
    		
    		Selector selector = sequence.selector();
    		while(!selector.end()){
    			System.out.println(selector.current() + " ");
    			selector.next();
    		}
    	}
    } /* Output:
    0 1 2 3 4 5 6 7 8 9
    */
    

    要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this:

    public class DotThis {
    	void f() { System.out.println("DotThis.f()");}
    	
    	public class Inner {
    		public DotThis outer() {
    			return DotThis.this;
    			// A plain "this" would be Inner's "this"
    		}
    	}
    	
    	public Inner inner() { return new Inner();}
    	
    	public static void main(String[] args){
    		DotThis dt = new DotThis();
    		DotThis.Inner dti = dt.inner();
    		dti.outer().f();
    	}
    } /* Output:
    DotThis.f()
    */
    

    要告知某个其他对象,去创建其某个内部类的对象,你必须在new表达式中提供对其他外部类对象的引用,这需要使用.new语法:

    public class DotNew {
    	public class Inner {}
    	
    	public static void main(String[] args){
    		DotNew dn = new DotNew();
    		DotNew.Inner dni = dn.new Inner();
    	}
    }
    

    要直接创建内部类的对象,你不能按照想象的方式,去引用外部类的名字DotNew,而必须使用外部类的对象来创建该内部类对象.

    在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地连接到创建它的外部类对象上。

    但如果你创建的是嵌套类(静态内部类),那就不需要对外部类对象的引用:

    public class Parcel3 {
    	class Contents {
    		private int i = 11;
    		public int value() { return i;}
    	}
    	
    	class Destination {
    		private String label;
    		Destination(String whereTo) { label = whereTo;}
    		String readLabel() { return label;}
    	}
    	
    	public static void main(String[] args){
    		Parcel3 p = new Parcel3();
    		
    		// Must use instance of outer class
    		// to create an instance of the inner class:
    		Parcel3.Contents c = p.new Contents();
    		Parcel3.Destination d = p.new Destination("Tasmania");
    	}
    }
    

    内部类与向上转型

    示例接口:

    public interface Destination {
    	String readLabel();
    }
    
    public interface Contents {
    	int value();
    }
    

    当取得一个指向基类或接口的引用时,甚至可能无法找出它的确切类型:

    class Parcel4 {
    	private class PContents implements Contents {
    		private int i = 11;
    		public int value() { return i;}
    	}
    	
    	protected class PDestination implements Destination {
    		private String label;
    		private PDestination(String whereTo){
    			label = whereTo;
    		}
    		public String readLabel() { return label;}
    	}
    	
    	public Destination destination(String s){
    		return new PDestination(s);
    	}
    	
    	public Contents contents(){
    		return PContents();
    	}
    }
    
    public class TestParcel {
    	public static void main(String[] args){
    		Parcel4 p = new Parcel4();
    		Contents c = p.contents();
    		Destination d = p.destination("Tasmania");
    		
    		// Illegal -- can't access private class
    		//! Parcel4.PContents pc = p.new PContents();
    	}
    }
    

    可以在一个方法里或者在任意的作用域内定义内部类。

    在方法的作用域内创建一个完整的内,称作局部内部类

    public class Parcel5{
    	public Destination destination(String s) {
    		class PDestination implements Destination {
    			private String label;
    			
    			private PDestination(String whereTo) {
    				label = whereTo;
    			}
    			public String readLabel() { return label;}
    		}
    		
    		return new PDestination(s);
    	}
    
    	public static void main(String[] args)}{
    		Parcel5 p = new Parcel5();
    		Destination d = p.destination("Tasmania");
    	}
    }
    

    1. PDestination类是destination()方法的一部分,所以在destination()方法之外不能访问PDestination。注意出现在return后的向上转型。

    2. 在destination()方法内定义内部类,并不意味着在destination()方法执行完毕之后,PDestination就不可用了。

    3. 可以在同一个子目录下的任意类中,对某个内部类用标示符PDestination命名,这并不会有名字冲突。

    在任意的作用域内嵌入一个内部类:

    public class Parcel6 {
    	private void internalTracking(boolean b){
    		if(b){
    			class TrackingSlip {
    				private String id;
    				TrackingSlip(String s){
    					id = s;
    				}
    				String getSlip() { return id;}
    			}
    			
    			TrackingSlip ts = new TrackingSlip("X");
    			String s = ts.getSlip();
    		}
    		
    		// Can't use it here! Out of scope:
    		//! TrackingSlip ts = new TrackingSlip("X");
    	}
    	
    	public void track() { internalTracking(true); }
    	
    	public static void main(String[] args){
    		Parcel6 p = new Parcel6();
    		p.track();
    	}
    }
    

    TrackingSlip类被嵌入if语句,并不是说该类的创建是有条件的:

    1. 它其实是与别的类一起被编译过了

    2. 在定义TrackingSlip的作用域之外,它是不可用的

    匿名内部类

    public class Parcel7 {
    	public Contents contents() {
    		return new Contents() {	// Insert a class definition
    			private int i = 11;
    			public int value() { return i;}
    		};	// Semicolon required in this case
    	}
    	
    	public static void main(String[] args){
    		Parcel7 p = new Parcel7();
    		Contents c = p.contents();
    	}
    }
    

    这里,Contents是之前定义的接口。这种奇怪的语法指的是:“创建一个继承自Contents的匿名类的对象”,通过new表达式返回的引用被向上转型为对Contents的引用,上述匿名内部类的语法是下述形式的简化形式:

    public class Parcel7b {
    	class MyContents implements Contents {
    		private i = 11;
    		public int value() { return i;}
    	}
    	
    	public Contents contents() { return new MyContents();}
    	
    	public static void main(String[] args){
    		Parcel7b p = new Parcel7b();
    		Contents c = p.contents();
    	}
    }
    

    在匿名内部类中使用了默认的构造器来生成Contents,下面展示,如果你的基类需要一个有参数的构造器应该怎么办:

    public class Wrapping {
     private int i;
     public Wrapping(int x) { i = x;}
     public int value() { return i;}
    }

    public class Parcel8 { public Wrapping wrapping(int x) { // Base constructor call: return new Wrapping(x) { // Pass constructor argument public int value(){ return super.value() * 47; } }; // Semicolon required } public static void main(Sring[] args){ Parcel8 p = new Parcel8(); Wrapping w = p.wrapping(10); } }

     如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的:

    public class Parcel9 {
    	// Argument must be final to use inside
    	// anonymous inner class:
    	public Destination destination(final String dest) {
    		return new Destination() {
    			private String label = dest;
    			public String readLabel() { return label;}
    		};
    	}
    	
    	public static void main(String[] args){
    		Parcel9 p = new Parcel9();
    		Destination d = p.destination("Tasmania");
    	}
    }
    

    如果想做一些类似构造器的行为,在匿名类中不可能有命名构造器(因为它根本没有名字!),但通过实例初始化,就能够达到匿名内部类创建一个构造器的效果。

    目标效果:

    public class AnonymousConstructor {
    	public static Base getBase(int i){
    		return new Base(i){
    			{ 
    				print("Inside instance initializer"); 
    			}
    			
    			public void f(){
    				print("In anonymous f()");
    			}
    		};	
    	}
    	
    	public static void main(String[] args){
    		Base base = new getBase(47);
    		base.f();
    	}
    } /* Output:
    Base constructor, i = 47
    Inside instance initializer
    In anonymous f()
    */
    

    实例初始化的“parcel” 形式:

    public class Parcel10 {
    	public Destination destination(final String dest, final float price){
    		return new Destination() {
    			private int cost;
    			
    			// Instance initialization for each object:
    			{
    				cost = Math.round(price);
    				if(cost > 100)
    					System.out.println("Over budget!")
    			}
    			
    			private String label = dest;
    			public String readLabel() { return label;}
    		};
    	}
    	
    	public static void main(String[] args){
    		Parcel10 p = new Parcel10();
    		Destination d = p.destination("Tasmania", 101.395F);
    	}
    } /* Output:
    Over budget!
    */
    

    运用匿名内部类实现工厂方法:

    import static net.mindview.util.Print.*;
    
    interface Service {
    	void method1();
    	void method2();
    }
    
    interface ServiceFactory {
    	Service getService();
    }
    
    class Implementation1 implements Service {
    	private Implementation1() {}
    	
    	public method1 { print("Implementation1 method1");}
    	public method2 { print("Implementation1 method2");}
    	
    	public static ServiceFactory factory = 
    		new ServiceFactory() {
    			public Service getService(){
    				return new Implementation1();
    			}
    		}
    }
    
    class Implementation2 implements Service {
    	private Implementation2() {}
    	
    	public method1 { print("Implementation2 method1");}
    	public method2 { print("Implementation2 method2");}
    	
    	public static ServiceFactory factory = 
    		new ServiceFactory(){
    			public getService(){
    				return new Implementation2();
    			}
    		}
    }
    
    public class Factories {
    	public static void serviceConsumer(ServiceFactory fact){
    		Service s = fact.getService();
    		s.method1();
    		s.method2();
    	}
    	
    	public static void main(String[] args){
    		serviceConsumer(Implementation1.factory);
    		// Implementations are completely interchangeable:
    		serviceConsumer(Implementation2.factory);
    	}
    } /* Output:
    Implementation1 method1
    Implementation1 method2
    Implementation2 method1
    Implementation2 method2
    */
    

    Game类也可以经由同样的改进:

    import static net.mindview.util.Print.*;
    
    interface Game { boolean move();}
    interface GameFactory { Game getGame();}
    
    class Checkers implements Game {
    	private Checkers() {}
    	
    	private int moves = 0;
    	private static final int MOVES = 3;
    	
    	public boolean move() {
    		print("Checkers move " + moves);
    		return ++moves != MOVES;
    	}
    	
    	public static GameFactory factory = new GameFactory() {
    		public Game getGame() { return new Checkers(); }
    	};
    }
    
    class Chess implements Game {
    	private Chess() {}
    	private int moves = 0;
    	private static final int MOVES = 4;
    	
    	public boolean move() {
    		print("Chess move " + moves);
    		return ++moves != MOVES;
    	}
    	
    	public static GameFactory factory = new GameFactory() {
    		public Game getGame() { return new Chess();}
    	};
    }
    
    public class Games {
    	public static void playGame(GameFactory factory) {
    		Game s = factory.getGame();
    		while(s.move());
    	}
    	
    	public static void main(String[] args){
    		playGame(Checkers.factory);
    		playGame(Chess.factory);
    	}
    } /* Output:
    Checkers move 0
    Checkers move 1
    Checkers move 2
    Chess move 0
    Chess move 1
    Chess move 2
    Chess move 3
    */
    

    嵌套类

    1. 要创建嵌套类的对象,并不需要其外围类的对象

    2. 不能从嵌套类中访问非静态的外围类对象

    普通内部类的字段与方法只能放在类的外部层次,所以普通内部类不能有static数据和static字段。但是嵌套类可以包含所有这些东西

    public class Parcel11 {
    	private static class ParcelContents implements Contents {
    		private int i = 11;
    		public int value() { return i;}
    	}
    	
    	protected static class ParcelDestination implements Destination {
    		private String label;
    		private ParcelDestination(String whereTo){
    			label = whereTo;
    		}
    		public String readLabel() { return label;}
    		
    		// Nested classes can contain other static elements:
    		public static void f() {}
    		static int x = 10;
    		static class AnotherLevel {
    			public static void f() {}
    			static int x = 10;
    		}
    	}
    	
    	public static Destination destination(String s){
    		return new ParcelDestination(s);
    	}
    	
    	public static Contents contents(){
    		return new ParcelContents();
    	}
    	
    	public static void main(String[] args){
    		Contents c = new contents();
    		Destination d = destination("Tasmania");
    	}
    }
    

    正常情况下,不能在接口内放置任何代码,但嵌套类可以作为接口的一部分。放到接口中的任何类都是public和static的。因为类是static的,所以这并不违反接口的规则。甚至,可以在内部类中实现其外围的接口:

    //: innerclasses/ClassInInterface.java
    // {main: ClassInInterface$Test}

    public interface ClassInInterface { void howdy(); class Test implements ClassInInterface { public void howdy(){ System.out.println("Howdy!"); } public static void main(String[] args){ new Test().howdy(); } } } /* Output: Howdy! */

    要运行以上代码,执行java ClassInInterface$Test即可,在Unix/Linux中,符号$必须转义。

    可以使用嵌套类来放置测试代码:(运行这个程序,执行java TestBed$Tester即可。)

    //: innerClasses/TestBed.java
    // Putting test code in a nested class.
    // {main: TestBed$Tester}
    
    public class TestBed {
    	public void f() { System.out.println("f()");}
    	
    	public static class Tester {
    		public static void main(String[] args){
    			TestBed t = new TestBed();
    			t.f();
    		}
    	}
    } /* Output:
    f()
    */

    这生成了一个独立的类TestBed$Tester。 可以使用这个类来做测试,但不必在发布的产品中包含它,在将产品打包前可以简单地删除TestBed$Tester.class文件。

    一个内部类被嵌套多少层并不重要,它能透明地访问所有它所嵌入的外围类的所有成员:

    class MNA {
    	private void f() {}
    	
    	class A {
    		private void g() {}
    		
    		public class B {
    			void h(){
    				g();
    				f();
    			}
    		}
    	}
    }
    
    public class MultiNestingAccess {
    	public static void main(String[] args){
    		MNA mna = new MNA();
    		MNA.A mnaa = mna.new A();
    		MNA.A.B mnaab = mnaa.new B();
    		mnaab.h();
    	}
    }
    

    内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。也就是说,内部类允许继承多个非接口类。让我们考虑这样一种情形:必须在一个类中以某种方式实现两个接口。有两种方式:

    1. 使用单一类

    2. 使用内部类

    package innerclasses;
    
    interface A {}
    interface B {}
    
    // 1. Use only one class class X implements A, B {}

    // 2. Use inner class class Y implements A { B makeB(){ // Anonymous inner class: return new B() {}; } } public class MultiInterfaces { static void takesA(A a) {} static void takesB(B b) {} public static void main(String[] args)}{ X x = new X(); Y y = new Y(); takesA(x); takesA(y); takesB(x); takesB(y.makeB()); } }

    如果拥有的是抽象的类或具体的类,而不是接口, 那就只能选择内部类实现多重继承:

    // With concrete or abstract classes, inner
    // classes are the only way to produce the effect
    // of "multiple implementation inheritance."
    package innerclasses;
    
    class D {}
    abstract class E {}
    
    class Z extends D {
    	E makeE() { return new E() {}; }
    }
    
    public class MultiImplementation {
    	static void takesD(D d) {}
    	static void takesE(E e) {}
    	public static void main(String[] args){
    		Z z = new Z();
    		takesD(z);
    		takesE(z.makeE());
    	}
    }
    

    闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。可以看出,内部类是面向对象的闭包。

    通过内部类提供闭包的功能是优良的解决方案, 它比指针更灵活、更安全:

    // Using inner class for callbacks
    package innerclasses;
    import static net.mindview.util.Print.*;
    
    interface Incrementable {
    	void increment();
    }
    
    // Very simple to just implement the interface:
    class Callee1 implements Incrementable {
    	private int i = 0;
    	
    	public void increment() {
    		++i;
    		print(i);
    	}
    } 
    
    class MyIncrement {
    	public void increment() { print("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;
    		print(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();
    	}
    } /* Output:
    Other operation
    1
    1
    2
    Other operation
    2
    Other operation
    3
    */

    应用程序框架(application framework)就是被设计用以解决某类特定问题的一个类或一组类。

    要运用某个应用程序框架,通常是继承一个类或多个类,并覆盖某些方法。

    控制框架(control framework)是一类特殊的应用程序框架,它用来解决响应事件的需求。主要用来响应事件的系统被称为事件驱动系统。

    下面的例子包含了某些实现:

    // The common methods for any control event.
    package innerclasses.controller;
    
    public abstract class Event {
    	private long eventTime;
    	protected final long delayTime;
    	
    	public Event(long delayTime) {
    		this.delayTime = delayTime;
    		start();
    	}
    	
    	public void start(){ // Allows restarting
    		eventTime = System.nanoTime() + delayTime;
    	}
    	
    	public boolean ready() {
    		return System.nanoTime() >= eventTime;
    	}
    	
    	public abstract void action();
    }
    

    下面的文件包含了一个用来管理并触发事件的实际控制框架:

    // The reusable framework for control system.
    package innerclasses.controller;
    import java.util.*;
    
    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);
    				}
    			}
    			
    		}
    	}
    }
    

    使用内部类,可以在单一的框架里面产生对同一个基类Event的多种导出版本。对于温室系统的每一种行为,都继承一个新的Event内部类,并在要实现的action()中编写控制代码。

    温室控制系统:

    // This produces a specific application of the
    // control system, all in a single class. Inner
    // classes allow you to encapsulate different
    // functionality for each type of event.
    import innerclasses.controller.*;
    
    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 code 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";}
    	}
    }
    

    下面的类通过创建一个GreenhouseControls对象,并添加各种不同的Event对象来配置该系统:

    // Configure and execute the greenhouse system.
    // {Args: 5000}
    import innerclasses.controller.*;
    
    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),m
    			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();
    	}
    } /* Output:
    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
    */
    

    内部类的继承

    因为内部类的构造器必须连接到指向外围类对象的引用,所以在继承内部类的时候,事情会变得复杂。问题在于,那个指向外围类对象的“秘密的”引用必须被初始化,而在导出类中不再存在可连接的默认对象。

    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 i1 = new InheritInner(wi);
    	}
    }
    

    InheritInner只能继承自内部类,且必须在构造器内使用如下语法:enclosingClassReference.super();,这样才能提供必要的引用,然后程序才能编译通过。

    “覆盖”内部类就好像它是外围类的一个方法,其实并不起作用。

    import static net.mindview.util.Print.*;
    
    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()
    */
    

    这个例子说明了,当继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。

    当然,明确地继承某个内部类也是可以的:

    import static net.mindview.util.Print.*;
    
    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()
    */
    

    局部内部类(在方法体里面创建)

    1. 局部内部类不能有访问说明符

    2. 可以访问当前代码块内的所有常量

    3. 可以访问外围类的所有成员

    局部内类与匿名内部类创建的比较:

    // Holds a sequence of Objects.
    import static net.mindview.util.Print.*;
    
    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
    				print("LocalCounter()");
    			}
    			
    			public int next() {
    				printnb(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:
    			{
    				print("Counter()");
    			}
    			
    			public int next(){
    				printnb(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)
    			print(c1.next());
    		for(int i = 0; i < 5; ++i)
    			print(c2.next());
    	}
    } /* Output:
    LocalCounter()
    Counter()
    Local inner 0
    Local inner 1
    Local inner 2
    Local inner 3
    Local inner 4
    Anonymous inner 5
    Anonymous inner 6
    Anonymous inner 7
    Anonymous inner 8
    Anonymous inner 9
    */
    

    每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息(此信息中产生一个"meta-class",叫做class对象)。

    内部类也必须产生一个.class文件以包含它们的信息。它们的命名规则是:外围类的名字加上“$”,再加上内部类的名字。

    例如,LocalInnerClass.java生成的.class文件包括:

    Counter.class

    LocalInnerClass$1.class

    LocalInnerClass$1LocalCounte.class

    LocalInnerClass$1LocalCounter.class

    LocalInnerClass.class

    以上中,如果内部类是匿名的,编译器会简单地产生一个数字作为其标示符。

  • 相关阅读:
    sourceTree push提交代码
    sourcetree 创建分支
    sourcetree 删除分支
    php 根据经纬度计算距离
    git linux服务器拉取代码sh脚本,批量拉取git代码
    百度地图-省市县联动加载地图 分类: Demo JavaScript 2015-04-26 13:08 531人阅读 评论(0) 收藏
    2020企业数字化转型的思考
    数据治理与企业数字化转型
    亚信科技入围中国大数据领域三大重磅榜单
    大数据智能分析的“六个特征”和“六个能力”
  • 原文地址:https://www.cnblogs.com/kid551/p/4316993.html
Copyright © 2011-2022 走看看