Thinking in Java from Chapter 10

From Thinking in Java 4th Editionjava

 

內部類安全

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
*/

 

當生成一個內部類的對象時,此對象與製造它的外圍對象之間就有了聯繫,它能訪問其外圍對象的全部成員。內部類擁有其外圍類的全部元素的訪問權:app

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語法:ide

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

要直接建立內部類的對象,你不能按照想象的方式,去引用外部類的名字DotNew,而必須使用外部類的對象來建立該內部類對象.測試

 

在擁有外部類對象以前是不可能建立內部類對象的。這是由於內部類對象會暗暗地鏈接到建立它的外部類對象上。ui

但若是你建立的是嵌套類(靜態內部類),那就不須要對外部類對象的引用:this

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");
	}
}

 

內部類與向上轉型spa

示例接口:

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

以上中,若是內部類是匿名的,編譯器會簡單地產生一個數字做爲其標示符。

相關文章
相關標籤/搜索