《Java编程思想》第十章 内部类
Posted zlz099
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Java编程思想》第十章 内部类相关的知识,希望对你有一定的参考价值。
1、将一个类的定义放到另一个类的内部,称为内部类。允许把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月20日 下午4:39:35 4 */ 5 public class Parcel1 { 6 class Contents{ 7 private int i = 11; 8 public int value(){return i;} 9 } 10 class Destination{ 11 private String label; 12 Destination(String whereTo){ 13 label = whereTo; 14 } 15 String readLable(){return label;} 16 } 17 public void ship(String dest){ 18 Contents c = new Contents(); 19 System.out.println(c.value()); 20 Destination d = new Destination(dest); 21 System.out.println(d.readLable()); 22 } 23 public static void main(String[] args) { 24 // TODO Auto-generated method stub 25 Parcel1 parcel1 = new Parcel1(); 26 parcel1.ship("Tasmania"); 27 } 28 }
2、内部类能访问其外围对象的所有成员,拥有外围类的所有元素的访问权。构建内部类对象时,需要一个指向其外围类对象的引用。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月20日 下午5:07:09 4 */ 5 public class Parcel2 { 6 class Contents{ 7 private int i = 11; 8 public int value(){return i;} 9 } 10 class Destination{ 11 private String label; 12 Destination(String whereTo){ 13 label = whereTo; 14 } 15 String readLable(){return label;} 16 } 17 public Destination to(String s){ 18 return new Destination(s); 19 } 20 public Contents contents(){ 21 return new Contents(); 22 } 23 public void ship(String dest){ 24 Contents c = new Contents(); 25 //System.out.println(c.value()); 26 Destination d = new Destination(dest); 27 System.out.println(d.readLable()); 28 } 29 public static void main(String[] args) { 30 // TODO Auto-generated method stub 31 Parcel2 p = new Parcel2(); 32 p.ship("Tasmania"); 33 Parcel2 q = new Parcel2(); 34 Parcel2.Contents c = q.contents(); 35 Parcel2.Destination d = q.to("Borneo"); 36 } 37 38 }
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月20日 下午5:13:32 4 */ 5 interface Selector{ 6 boolean end(); 7 Object current(); 8 void next(); 9 } 10 public class Sequence { 11 private Object[] items; 12 private int next = 0; 13 public Sequence(int size){items = new Object[size];} 14 public void add(Object x){ 15 if(next<items.length) 16 items[next++] = x; 17 } 18 private class SequeceSelector implements Selector{ 19 private int i = 0; 20 public boolean end(){return i == items.length;} 21 public Object current(){return items[i];} 22 public void next(){if(i<items.length) i++;} 23 } 24 public Selector selector(){ 25 return new SequeceSelector(); 26 } 27 public static void main(String[] args) { 28 // TODO Auto-generated method stub 29 Sequence sequence = new Sequence(10); 30 for(int i = 0; i<10;i++){ 31 sequence.add(Integer.toString(i)); 32 } 33 Selector selector = sequence.selector(); 34 while(!selector.end()){ 35 System.out.println(selector.current()+" "); 36 selector.next(); 37 } 38 } 39 40 }
3、需要生成对外部类对象的引用,则使用外部类名字后面加.this 如果想告知某些其他对象,去创建某个内部类的对象,则必须在new表达式中提供对其他外部类对象的引用,使用.new语法。要创建内部类的对象,要使用外部类的对象来创建内部类的对象。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月21日 下午3:56:37 4 */ 5 public class DotThis { 6 void f(){System.out.println("DoThis.f()");} 7 public class Inner{ 8 public DotThis outer(){ 9 return DotThis.this; 10 } 11 } 12 public Inner inner() { 13 return new Inner(); 14 } 15 public static void main(String[] args) { 16 // TODO Auto-generated method stub 17 DotThis dt = new DotThis(); 18 DotThis.Inner dti = dt.inner(); 19 dti.outer().f(); 20 } 21 22 }
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月21日 下午4:02:57 4 */ 5 public class Parcel3 { 6 class Contents{ 7 private int i = 11; 8 public int value(){return i;} 9 } 10 class Destination{ 11 private String label; 12 Destination(String whereTo){ 13 label = whereTo; 14 } 15 String readLable(){return label;} 16 } 17 18 public static void main(String[] args) { 19 // TODO Auto-generated method stub 20 Parcel3 p = new Parcel3(); 21 Parcel3.Contents c = p.new Contents(); 22 Parcel3.Destination d = p.new Destination("Tasmania"); 23 } 24 25 }
4、如果不需要内部类对象与外部类对象之间有联系,则可以将内部类声明为static,这称为嵌套类。嵌套类没有this方法。不能链接外部类。
5、嵌套类和普通内部类的区别:普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。
6、嵌套类可以作为接口的一部分。放入接口中的任何类都是public和static的。
7、如果要创建某些公共代码,使得他们可以被某个接口的所有不同实现所共有,则使用接口内部嵌套类方便。
8、多层嵌套类均可以访问其所嵌入的外围类的所有成员。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月21日 下午4:48:45 4 */ 5 class MNA{ 6 private void f(){System.out.println("f()");} 7 class A{ 8 private void g(){System.out.println("g()");} 9 public class B{ 10 void h(){ 11 System.out.println("h()"); 12 g(); 13 f(); 14 } 15 } 16 } 17 } 18 public class MultiNestingAccess { 19 public static void main(String[] args) { 20 // TODO Auto-generated method stub 21 MNA mna = new MNA(); 22 MNA.A mnaa = mna.new A(); 23 MNA.A.B mnaab = mnaa.new B(); 24 mnaab.h(); 25 } 26 27 }
9、为什么需要内部类:每个内部类都能独立的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,都对内部类没有影响。内部类有效的解决了多继承问题,允许继承多个非接口类型。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月21日 下午5:09:38 4 */ 5 interface Incrementable{ 6 void increment(); 7 } 8 9 class Callee1 implements Incrementable{ 10 private int i = 0; 11 public void increment() { 12 // TODO Auto-generated method stub 13 i++; 14 System.out.println(i); 15 } 16 } 17 18 class MyIncrement{ 19 public void increment(){System.out.println("Other operation");} 20 static void f(MyIncrement mi){mi.increment();} 21 } 22 23 class Callee2 extends MyIncrement{ 24 private int i = 0; 25 public void increment(){ 26 super.increment(); 27 i++; 28 System.out.println(i); 29 } 30 private class Closure implements Incrementable{ 31 public void increment(){ 32 Callee2.this.increment(); 33 } 34 } 35 Incrementable getCallbackReference(){ 36 return new Closure(); 37 } 38 } 39 40 class Caller{ 41 private Incrementable callbackReference; 42 Caller(Incrementable cbh) { 43 // TODO Auto-generated constructor stub 44 callbackReference = cbh; 45 } 46 void go(){callbackReference.increment();} 47 } 48 public class Callbacks { 49 50 public static void main(String[] args) { 51 // TODO Auto-generated method stub 52 Callee1 c1 = new Callee1(); 53 Callee2 c2 = new Callee2(); 54 MyIncrement.f(c2); 55 Caller caller1 = new Caller(c1); 56 Caller caller2 = new Caller(c2.getCallbackReference()); 57 caller1.go(); 58 caller1.go(); 59 caller2.go(); 60 caller2.go(); 61 } 62 }
10、如果拥有的是抽象的类或者具体的类,则只有内部类能实现多重继承。
11、闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。通过内部对象提供的闭包功能可以实现回调。
1 package controller; 2 /** 3 * @author zlz099: 4 * @version 创建时间:2017年9月25日 下午9:38:48 5 */ 6 public abstract class Event { 7 private long eventTime; 8 protected final long delayTime; 9 public Event(long delayTime){ 10 this.delayTime = delayTime; 11 start(); 12 } 13 public void start(){ 14 eventTime = System.nanoTime()+delayTime; 15 } 16 public boolean ready(){ 17 return System.nanoTime()>=eventTime; 18 } 19 public abstract void action(); 20 21 }
1 package controller; 2 3 import java.util.*; 4 5 /** 6 * @author zlz099: 7 * @version 创建时间:2017年9月25日 下午9:36:23 8 */ 9 public class Controller { 10 private List<Event> eventList = new ArrayList<Event>(); 11 public void addEvent(Event c){eventList.add(c);} 12 public void run(){ 13 while(eventList.size()>0){ 14 for(Event e : new ArrayList<Event>(eventList)) 15 if(e.ready()){ 16 System.out.println(e); 17 e.action(); 18 eventList.remove(e); 19 } 20 } 21 } 22 }
1 package controller; 2 3 import java.lang.Thread.State; 4 5 /** 6 * @author zlz099: 7 * @version 创建时间:2017年9月25日 下午9:48:46 8 */ 9 public class Greenhouse extends Controller{ 10 private boolean light = false; 11 public class LightOn extends Event{ 12 public LightOn(long delayTime){super(delayTime);} 13 public void action() { 14 // TODO Auto-generated method stub 15 light = true; 16 } 17 public String toString(){return "Light is on";} 18 } 19 public class LightOff extends Event{ 20 21 public LightOff(long delayTime){super(delayTime);} 22 public void action() { 23 // TODO Auto-generated method stub 24 light = false; 25 } 26 public String toString(){return "Light is off";} 27 } 28 private boolean water = false; 29 public class WaterOn extends Event{ 30 public WaterOn(long delayTime){super(delayTime);} 31 public void action() { 32 // TODO Auto-generated method stub 33 water = true; 34 } 35 public String toString(){return "greenhouse water is on";} 36 } 37 38 public class WaterOff extends Event{ 39 public WaterOff(long delayTime){super(delayTime);} 40 public void action() { 41 // TODO Auto-generated method stub 42 water = false; 43 } 44 public String toString(){return "greenhouse water is off";} 45 } 46 47 private String thermostat = "Day"; 48 public class ThermostatNight extends Event{ 49 public ThermostatNight(long delayTime){super(delayTime);} 50 public void action() { 51 // TODO Auto-generated method stub 52 thermostat = "Night"; 53 } 54 public String toString(){return "Thermostat on night setting";} 55 } 56 57 public class ThermostatDay extends Event{ 58 public ThermostatDay(long delayTime){super(delayTime);} 59 public void action() { 60 // TODO Auto-generated method stub 61 thermostat = "Day"; 62 } 63 public String toString(){return "Thermostat on day setting";} 64 } 65 66 public class Bell extends Event{ 67 public Bell(long delayTime){super(delayTime);} 68 public void action() { 69 // TODO Auto-generated method stub 70 addEvent(new Bell(delayTime)); 71 } 72 public String toString(){return "Ring!";} 73 } 74 public class Restart extends Event{ 75 private Event[] eventList; 76 public Restart(long delayTime,Event[] eventList){ 77 super(delayTime); 78 this.eventList = eventList; 79 for(Event e : eventList) 80 addEvent(e); 81 } 82 public void action(){ 83 for(Event e : eventList){ 84 e.start(); 85 addEvent(e); 86 } 87 start(); 88 addEvent(this); 89 } 90 public String toString(){ 91 return "Restarting system"; 92 } 93 } 94 public static class Terminate extends Event { 95 // TODO Auto-generated method stub 96 public Terminate(long delayTime){super(delayTime);} 97 public void action(){System.exit(0);} 98 public String toString(){return "Terminating";} 99 } 100 }
1 package controller; 2 /** 3 * @author zlz099: 4 * @version 创建时间:2017年9月26日 上午9:46:11 5 */ 6 public class GreenhouseController { 7 8 public static void main(String[] args) { 9 // TODO Auto-generated method stub 10 Greenhouse gs = new Greenhouse(); 11 gs.addEvent(gs.new Bell(900)); 12 Event[] eventList = { 13 gs.new ThermostatNight(0), 14 gs.new LightOn(200), 15 //gs.new LightOff(200), 16 gs.new LightOff(400), 17 gs.new WaterOn(600), 18 gs.new WaterOff(800), 19 gs.new ThermostatDay(1400) 20 }; 21 gs.addEvent(gs.new Restart(2000, eventList)); 22 if(args.length == 1) 23 gs.addEvent(new Greenhouse.Terminate((new Integer(args[0])))); 24 gs.run(); 25 } 26 27 }
12、内部类的构造器必须连接到指向其外围类对象的引用,所以继承内部类有点复杂。默认构造器不好使,且不能只是传递一个指向外围类对象的引用。此外,必须在构造器内使用如下算法:enclosingClassReference.super();才提供了必要的引用,编译才能通过。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月26日 上午10:00:39 4 * 内部类的继承 5 */ 6 class WithInner{ 7 class Inner{} 8 } 9 public class InheritInner extends WithInner.Inner{ 10 InheritInner(WithInner wi) { 11 // TODO Auto-generated constructor stub 12 wi.super(); 13 } 14 15 public static void main(String[] args) { 16 // TODO Auto-generated method stub 17 WithInner wi = new WithInner(); 18 InheritInner ii = new InheritInner(wi); 19 } 20 21 }
13、当继承某个外围类时,内部类不会发生神奇的变化。这两个内部类是独立的个体,各自在各自的命名空间中。当然,明确的继承某个内部类是可以的。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月26日 上午10:05:28 4 */ 5 class Egg{ 6 private Yolk y; 7 protected class Yolk{ 8 public Yolk(){System.out.println("Egg.Yolk()");} 9 } 10 public Egg(){ 11 System.out.println("new Egg()"); 12 y = new Yolk(); 13 } 14 } 15 public class BigEgg extends Egg { 16 public void Yolk(){System.out.println("BigEgg.Yolk()");} 17 public static void main(String[] args) { 18 // TODO Auto-generated method stub 19 new BigEgg(); 20 } 21 22 }
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月26日 上午10:57:38 4 */ 5 class Egg2{ 6 protected class Yolk{ 7 public Yolk(){ 8 System.out.println("Egg2.Yolk()"); 9 } 10 public void f(){System.out.println("Egg2.Yolk.f()");} 11 } 12 private Yolk y = new Yolk(); 13 public Egg2(){System.out.println("New Egg2()");} 14 public void insertYolk(Yolk yy){y =yy;} 15 public void g(){y.f();} 16 } 17 public class BigEgg2 extends Egg2{ 18 public class Yolk extends Egg2.Yolk{ 19 public Yolk(){System.out.println("BigEgg2.Yolk()");} 20 public void f(){System.out.println("BigEgg2.Yolk.f()");} 21 } 22 public BigEgg2(){insertYolk(new Yolk());} 23 public static void main(String[] args) { 24 // TODO Auto-generated method stub 25 Egg2 e2 = new BigEgg2(); 26 e2.g(); 27 } 28 29 }
14、局部内部类可以在代码块内创建内部类,不能有访问说明符,但可以访问当前代码块内的常量以及此外围类的所有成员。
1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月26日 上午11:12:03 4 */ 5 interface Counter{ 6 int next(); 7 } 8 public class LocalInnerClass { 9 private int count = 0; 10 Counter getCounter (final String name){ 11 class LocalCounter implements Counter{ 12 public LocalCounter(){ 13 System.out.println("LocalCounter()"); 14 } 15 public int next(){ 16 System.out.println(name); 17 return count++; 18 } 19 } 20 return new LocalCounter(); 21 } 22 Counter getCounter2(final String name){ 23 return new Counter() { 24 { 25 System.out.println("Counter()"); 26 } 27 @Override 28 public int next() { 29 // TODO Auto-generated method stub 30 System.out.println(name); 31 return count++; 32 } 33 }; 34 } 35 public static void main(String[] args) { 36 // TODO Auto-generated method stub 37 LocalInnerClass lic = new LocalInnerClass(); 38 Counter 39 c1=lic.getCounter("Local inner "); 40 Counter 41 c2=lic.getCounter2("Anonymous inner "); 42 43 for(int i = 0; i<5; i++){ 44 System.out.println(c1.next()); 45 } 46 for(int i = 0; i<5; i++){ 47 System.out.println(c2.next()); 48 } 49 } 50 51 }
15、使用局部内部类而不是匿名内部类的理由是我们需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。即需要不止一个该内部类的而对象。
以上是关于《Java编程思想》第十章 内部类的主要内容,如果未能解决你的问题,请参考以下文章