第10章 内部类
练习1:
编写一个名为Outer的类,它包含一个名为Inner的类。在Outer中添加一个方法,它返回一个Inner类型的对象。在main()中,创建并初始化一个指向某个Inner对象的引用。
略。之前的习题中已经多次这样操作。
练习2:
创建一个类,它持有一个String,并且有一个显示这个String的toString方法。将你的新类的若干个对象添加到一个Sequence对象中,然后显示他们。
略。添加完成以后循环输出打印即可。
练习3:
修改练习1,使得Outer类包含一个private String域(由构造器初始化),而Inner包含一个显示这个域的toString方法。创建一个Inner类型的对象并显示它。
略。新增一个方法调用即可。
练习4:
在Sequence.SequenceSelector类中增加一个方法,它可以生成对外部类Sequence的引用。
代码
package selector;
public class Sequence {
private Object[] items;
private int next = 0;
public Sequence(int size) {
items = new Object[size];
}
public void add(Object x) {
if (next < items.length) {
items[next++] = x;
}
}
private class SequenceSelector implements Selector {
public Sequence outer() {
System.out.println("outer");
return Sequence.this;
}
private int i = 0;
@Override
public boolean end() {
return i == items.length;
}
@Override
public Object current() {
return items[i];
}
@Override
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));
}
SequenceSelector selector = (SequenceSelector) sequence.selector();
while (!selector.end()) {
System.out.print(selector.current() + " ");
selector.next();
}
System.out.println();
System.out.println(selector.outer());
}
}
输出
0 1 2 3 4 5 6 7 8 9
outer
selector.Sequence@4554617c
练习5:
创建一个包含内部类的类,在另一个独立的类中,创建此内部类的实例。
创建内部类,如果内部类非静态,需要先创建外部类。方式:外部类.new。
代码
package selector;
public class AClassWithInnerClass {
public class InnerTest {
public InnerTest() {
System.out.println("create InnerTest");
}
}
}
package selector;
public class TestOtherClass {
public AClassWithInnerClass.InnerTest createSequenceInnerClass() {
AClassWithInnerClass a = new AClassWithInnerClass();
return a.new InnerTest();
}
public static void main(String[] args) {
TestOtherClass testOtherClass = new TestOtherClass();
System.out.println(testOtherClass.createSequenceInnerClass());
}
}
输出
create InnerTest
selector.AClassWithInnerClass$InnerTest@4554617c
练习6:
在第一个包中创建一个至少由一个方法的接口。然后在第二个包内创建一个类,在其中增加一个protected的内部类以实现那个接口。在第三个包中,继承这个类,并在一个方法中返回该protected内部类的对象,在返回的时候向上转型为第一个包中的接口的类型。
代码
package testInterface;
public interface Instrument {
void toning();
void play();
void maintain();
}
package innerClassPackage;
import testInterface.Instrument;
public class AClassWithinInnerClass {
protected class Guitar implements Instrument {
//构造器需要声明为public
public Guitar() {
System.out.println("create guitar");
}
@Override
public void toning() {
}
@Override
public void play() {
}
@Override
public void maintain() {
}
}
}
package referencePackage;
import innerClassPackage.AClassWithinInnerClass;
import testInterface.Instrument;
public class PlayInstrument extends AClassWithinInnerClass {
public Instrument getInstrument() {
return new Guitar();
}
public static void main(String[] args) {
PlayInstrument playInstrument = new PlayInstrument();
System.out.println(playInstrument.getInstrument());
}
}
输出
create guitar
innerClassPackage.AClassWithinInnerClass$Guitar@4554617c
通过该题可以知道内部类的默认构造器和内部类的权限默认是相同的,如果为protected则只能为包内访问和导出类可访问,如果想要继承自外部类的导出类可访问父类的导出类,需要将父类的protected内部类的构造器修改为public权限。
练习7:
创建一个含有private域和private方法的类。创建一个内部类,他有一个方法可用来修改外围类的域,并调用外围类的方法。在外围类的另一个方法中,创建此内部类的对象,并且调用它的方法,然后说明对外围类对象的影响。
代码
package innerClassPackage;
import static testPackage.MyPrint.*;
public class ChangeOuter {
private int i = 1;
private void tellUs() {
println("ha ha ha");
}
public class ChangeInner {
public void tellByThis() {
println("innerTell");
tellUs();
}
public int getAndChangeOutInt() {
println("inner getInt");
i++;
return i;
}
}
public void doInner() {
ChangeInner inner = new ChangeInner();
println(inner.getAndChangeOutInt());
inner.tellByThis();
}
public static void main(String[] args) {
ChangeOuter changeOuter = new ChangeOuter();
changeOuter.doInner();
}
}
输出
inner getInt
2
innerTell
ha ha ha
说明内部类可以操作外部类的所有信息。
练习8:
确定外部类是否可以访问其内部类的private元素。
代码
package innerClassPackage;
import static testPackage.MyPrint.*;
public class ChangeOuter {
private int i = 1;
private void tellUs() {
println("ha ha ha");
}
public class ChangeInner {
private int innerInt = 0;
public void tellByThis() {
println("innerTell");
tellUs();
}
public int getAndChangeOutInt() {
println("inner getInt");
i++;
return i;
}
}
public void doInner() {
ChangeInner inner = new ChangeInner();
println(inner.getAndChangeOutInt());
inner.tellByThis();
}
public int getInnerInt() {
ChangeInner inner = new ChangeInner();
return inner.innerInt;
}
public static void main(String[] args) {
ChangeOuter changeOuter = new ChangeOuter();
changeOuter.doInner();
println(changeOuter.getInnerInt());
}
}
输出
inner getInt
2
innerTell
ha ha ha
0
练习9:
创建一个至少有一个方法的接口。在某个方法内定义一个内部类以实现此接口,这个方法返回对此接口的引用。
代码
package innerClassPackage;
import testInterface.Instrument;
public class Encore {
public Instrument playAgain() {
class Harp implements Instrument {
@Override
public void toning() {
}
@Override
public void play() {
System.out.println("play harp");
}
@Override
public void maintain() {
}
}
return new Harp();
}
public static void main(String[] args) {
Encore encore = new Encore();
encore.playAgain().play();
}
}
输出
play harp
练习10:
重复前一个练习,但将内部类定义在某一个方法一个作用域内。
代码
package testPackage;
import testInterface.Instrument;
public class Piano implements Instrument {
@Override
public void toning() {
}
@Override
public void play() {
System.out.println("play the piano");
}
@Override
public void maintain() {
}
}
package innerClassPackage;
import testInterface.Instrument;
import testPackage.Piano;
public class Encore {
public Instrument playAgainInstrument(boolean isNew) {
if (isNew) {
class Harp implements Instrument {
@Override
public void toning() {
}
@Override
public void play() {
System.out.println("play harp");
}
@Override
public void maintain() {
}
}
return new Harp();
}
return new Piano();
}
public static void main(String[] args) {
Encore encore = new Encore();
encore.playAgainInstrument(true).play();
encore.playAgainInstrument(false).play();
}
}
输出
play harp
play the piano
练习11:
创建一个private内部类,让他实现一个public接口。写一个方法,它返回一个指向此private内部类的实例的引用,并将此引用向上转型为该接口类型。通过尝试向下转型,说明此内部类被完全隐藏了。
代码
package innerClassPackage;
import testInterface.Instrument;
public class CreateInstrument {
private class Violin implements Instrument{
@Override
public void toning() {
}
@Override
public void play() {
System.out.println("play the violin");
}
@Override
public void maintain() {
}
}
public Violin getViolin(){
return new Violin();
}
public static void main(String[] args) {
CreateInstrument createInstrument = new CreateInstrument();
Instrument instrument = createInstrument.getViolin();
CreateInstrument.Violin violin = (CreateInstrument.Violin)instrument;
violin.play();
}
}
package innerClassPackage;
import testInterface.Instrument;
public class OtherPlay {
public static void main(String[] args) {
CreateInstrument createInstrument = new CreateInstrument();
Instrument instrument = createInstrument.getViolin();
//编译报错 CreateInstrument.Violin violin...
}
}
由此说明private内部类对外部类完全隐藏。
练习12:
重复练习7,这次使用匿名内部类。
代码
package innerClassPackage;
import static testPackage.MyPrint.*;
public class ToDo12 {
private int i = 1;
private void tellUs() {
println("ha ha ha");
}
public abstract class ChangeInner {
public void tellByThis() {
println("innerTell");
tellUs();
}
public int getAndChangeOutInt() {
println("inner getInt");
i++;
return i;
}
abstract void nothing();
}
public void doInner() {
ChangeInner inner = new ChangeInner() {
@Override
void nothing() {
println("do nothing");
}
};
println(inner.getAndChangeOutInt());
inner.tellByThis();
inner.nothing();
}
public static void main(String[] args) {
ToDo12 changeOuter = new ToDo12();
changeOuter.doInner();
}
}
输出
inner getInt
2
innerTell
ha ha ha
do nothing
练习13:
重复练习9,这次使用匿名内部类。
代码
package innerClassPackage;
import testInterface.Instrument;
public class Todo13 {
public Instrument playAgain() {
abstract class Harp implements Instrument {
@Override
public void toning() {
}
@Override
public void play() {
System.out.println("play harp");
}
}
return new Harp() {
@Override
public void maintain() {
System.out.println("goon playing");
}
};
}
public static void main(String[] args) {
Todo13 encore = new Todo13();
encore.playAgain().play();
encore.playAgain().maintain();
}
}
输出
play harp
goon playing
练习14:
修改interfaces/HorrorShow.java,用匿名类实现DangerousMonster和Vampire。
略。
练习15:
创建一个类,他有非默认的构造器(即需要参数的构造器),并且没有默认构造器(没有无参构造器)。创建第二个类,它包含一个方法,能够返回对第一个类的对象的引用,通过写一个继承自第一个类的匿名内部类,来创建一个返回对象。
代码
package innerClassPackage;
public abstract class FirstAbstractClass {
public FirstAbstractClass(int i) {
System.out.println("created");
System.out.println(i);
}
abstract void output();
}
package innerClassPackage;
public class ToTest {
public FirstAbstractClass getIt(int i) {
return new FirstAbstractClass(i) {
@Override
void output() {
System.out.println("nothing");
}
};
}
public static void main(String[] args) {
ToTest test = new ToTest();
FirstAbstractClass firstAbstractClass = test.getIt(10);
firstAbstractClass.output();
}
}
输出
created
10
nothing
练习16:
修改第9章练习18的解决方案,让它使用匿名内部类。
代码
package testPackage;
import static testPackage.MyPrint.*;
public interface Cycle {
public void produce();
public static class Unicycle implements Cycle {
private Unicycle() {
}
@Override
public void produce() {
println("Unicycle produce");
}
public static ProduceFactory unicycleFactory = new ProduceFactory() {
@Override
public Cycle produceCycle() {
println("UnicycleFactory");
return new Unicycle();
}
};
}
public static class Bicycle implements Cycle {
private Bicycle() {
}
@Override
public void produce() {
println("Bicycle produce");
}
public static ProduceFactory bicycleFactory = new ProduceFactory() {
@Override
public Cycle produceCycle() {
println("BicycleFactory");
return new Bicycle();
}
};
}
public static class Tricycle implements Cycle {
private Tricycle() {
}
@Override
public void produce() {
println("Tricycle produce");
}
public static ProduceFactory tricycleFactory = new ProduceFactory() {
@Override
public Cycle produceCycle() {
println("TricycleFactory");
return new Tricycle();
}
};
}
interface ProduceFactory {
Cycle produceCycle();
}
class Cycles {
static void produceCycle(ProduceFactory produceFactory) {
produceFactory.produceCycle().produce();
}
public static void main(String[] args) {
produceCycle(Unicycle.unicycleFactory);
produceCycle(Bicycle.bicycleFactory);
produceCycle(Tricycle.tricycleFactory);
}
}
}
输出
UnicycleFactory
Unicycle produce
BicycleFactory
Bicycle produce
TricycleFactory
Tricycle produce
练习17:
修改第9章练习19的解决方案,让他使用匿名内部类。
代码
package testPackage;
import static testPackage.MyPrint.*;
public interface Game {
void play();
class Coins implements Game {
private Coins() {
}
@Override
public void play() {
println("tossing");
}
public static GameFactory coinFactory = new GameFactory() {
@Override
public Game getGame() {
return new Coins();
}
};
}
class Throw implements Game {
private Throw() {
}
@Override
public void play() {
println("throwing");
}
public static GameFactory ThrowFactory = new GameFactory() {
@Override
public Game getGame() {
return new Throw();
}
};
}
interface GameFactory {
Game getGame();
}
class Player {
static void playGames(GameFactory factory) {
factory.getGame().play();
}
public static void main(String[] args) {
playGames(Coins.coinFactory);
playGames(Throw.ThrowFactory);
}
}
}
输出
tossing
throwing
通过此方法,没有必要创建作为工厂的具名类,可以简化代码。
练习18:
创建一个包含嵌套类的类。在main()中创建其内部类的实例。
略。
练习19:
创建一个包含了内部类的类,而此内部类又包含有内部类。使用嵌套类重复这个过程。注意编译器生成的.class文件的名字。
代码
public class MultiplyInnerClass {
static class A{
// static class B{
//
// }
}
}
public class MultiplyInnerClass {
static class A{
static class B{
}
}
}
练习20:
创建一个包含嵌套类的接口,实现此接口并创建嵌套类的实例。
代码
public interface TestStaticInnerClass {
static class InnerClass implements TestStaticInnerClass {
public void out() {
System.out.println("InnerClass out");
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.out();
}
}
}
InnerClass out
练习21:
创建一个包含嵌套类的接口,该嵌套类中有一个static方法,它将调用接口中的方法并显示结果。实现这个接口,并将这个实现的一个实例传递给这个方法。
代码
public interface TestStaticInnerClass {
void out();
static class InnerClass implements TestStaticInnerClass {
public void out(TestStaticInnerClass testStaticInnerClass) {
testStaticInnerClass.out();
}
@Override
public void out() {
System.out.println("InnerClass out");
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.out(innerClass);
}
}
}
输出
InnerClass out
练习22:
实现Sequence.java中的reverseSelector方法。
代码
package selector;
public class Sequence {
private Object[] items;
private int next = 0;
public Sequence(int size) {
items = new Object[size];
}
public void add(Object x) {
if (next < items.length) {
items[next++] = x;
}
}
private class SequenceSelector implements Selector {
public Sequence outer() {
System.out.println("outer");
return Sequence.this;
}
private int i = 0;
@Override
public boolean end() {
return i == items.length;
}
@Override
public Object current() {
return items[i];
}
@Override
public void next() {
if (i < items.length) {
i++;
}
}
}
public Selector selector() {
return new SequenceSelector();
}
private class ReveresSelector implements Selector {
public Sequence outer() {
System.out.println("outer");
return Sequence.this;
}
private int i = 0;
@Override
public boolean end() {
return i == items.length;
}
@Override
public Object current() {
return items[items.length - i - 1];
}
@Override
public void next() {
if (i < items.length) {
i++;
}
}
}
public Selector getRevereSelector() {
return new ReveresSelector();
}
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.getRevereSelector();
while (!selector.end()) {
System.out.print(selector.current() + " ");
selector.next();
}
System.out.println();
}
}
输出
9 8 7 6 5 4 3 2 1 0
练习23:
创建一个接口U,它包含三个方法。创建第一个类A,它包含一个方法,在此方法中通过创建一个匿名内部类,来生成指向U的引用。创建第二个类B,它包含一个由U够成的数组。B应该有几个方法,第一个方法可以接受对U的引用并存储到数组中;第二方法将数组中的引用设为null对象;第三个方法遍历此数组,并在U中调用这些方法。在main()中,创建一组A的对象和一个B的对象。用那些A类对象所产生的U类型的引用填充B对象的数组。使用B回调所有A的对。再从B中移除某些U的引用。
略。
练习24:
在GreenhouseControls.java中增加一个Event内部类,用以打开、关闭风扇。配置GreenhouseControler.java以使用这些新的Event对象。
代码
package greenHouse;
import java.util.ArrayList;
import java.util.List;
public class Controller {
private List<Event> events = new ArrayList<Event>();
public void addEvent(Event event) {
events.add(event);
}
public void run() {
while (events.size() > 0) {
for (Event event : new ArrayList<>(events)) {
if (event.ready()) {
System.out.println(event);
event.action();
events.remove(event);
}
}
}
}
}
package greenHouse;
public abstract class Event {
private long eventTime;
protected final long delayTime;
public Event(long delayTime) {
this.delayTime = delayTime;
}
public void start() {
eventTime = System.nanoTime() + delayTime;
}
public boolean ready() {
return System.nanoTime() >= eventTime;
}
public abstract void action();
}
package greenHouse;
import com.sun.xml.internal.ws.policy.EffectiveAlternativeSelector;
public class GreenHouseControls extends Controller {
private boolean light = false;
public class LightOn extends Event {
public LightOn(long delayTime) {
super(delayTime);
}
@Override
public void action() {
light = true;
}
@Override
public String toString() {
return "light is on";
}
}
public class LightOff extends Event {
public LightOff(long delayTime) {
super(delayTime);
}
@Override
public void action() {
light = false;
}
@Override
public String toString() {
return "light is off";
}
}
private boolean water = false;
public class WaterOn extends Event {
public WaterOn(long delayTime) {
super(delayTime);
}
@Override
public void action() {
water = true;
}
@Override
public String toString() {
return "greenHouse water is on";
}
}
public class WaterOff extends Event {
public WaterOff(long delayTime) {
super(delayTime);
}
@Override
public void action() {
water = false;
}
@Override
public String toString() {
return "greenhouse water is off";
}
}
private boolean fan = false;
public class FanOn extends Event {
public FanOn(long delayTime) {
super(delayTime);
}
@Override
public void action() {
fan = true;
}
@Override
public String toString() {
return "turn on the fan";
}
}
public class FanOff extends Event {
public FanOff(long delayTime) {
super(delayTime);
}
@Override
public void action() {
fan = false;
}
@Override
public String toString() {
return "turn off the fan";
}
}
private String thermostat = "Day";
public class ThermostatNight extends Event {
public ThermostatNight(long delayTime) {
super(delayTime);
}
@Override
public void action() {
thermostat = "Night";
}
@Override
public String toString() {
return "Thermostat on night setting";
}
}
public class ThermostatDay extends Event {
public ThermostatDay(long delayTime) {
super(delayTime);
}
@Override
public void action() {
thermostat = "Day";
}
@Override
public String toString() {
return "Thermostat on day setting";
}
}
public class Bell extends Event {
public Bell(long delayTime) {
super(delayTime);
}
@Override
public void action() {
addEvent(new Bell(delayTime));
}
@Override
public String toString() {
return "Ding";
}
}
public class Restart extends Event {
private Event[] events;
public Restart(long delayTime, Event[] events) {
super(delayTime);
this.events = events;
for (Event e : events) {
addEvent(e);
}
}
@Override
public void action() {
for (Event event : events) {
event.start();
addEvent(event);
}
start();
addEvent(this);
}
@Override
public String toString() {
return "restart System";
}
}
public static class Terminate extends Event {
public Terminate(long delayTime) {
super(delayTime);
}
@Override
public void action() {
System.exit(0);
}
@Override
public String toString() {
return "Termiating";
}
}
public static void main(String[] args) {
GreenHouseControls greenHouseController = new GreenHouseControls();
greenHouseController.addEvent(greenHouseController.new Bell(900));
Event[] events = new Event[]{
greenHouseController.new ThermostatNight(0),
greenHouseController.new LightOn(200),
greenHouseController.new LightOff(400),
greenHouseController.new WaterOn(600),
greenHouseController.new WaterOff(800),
greenHouseController.new ThermostatDay(1400),
greenHouseController.new FanOn(100),
greenHouseController.new FanOff(700),
};
greenHouseController.addEvent(greenHouseController.new Restart(2000, events));
if (args.length == 1) {
greenHouseController.addEvent(new GreenHouseControls.Terminate(new Integer(args[0])));
}
greenHouseController.run();
}
}
输出
Ding
Thermostat on night setting
light is on
light is off
greenHouse water is on
greenhouse water is off
Thermostat on day setting
turn on the fan
turn off the fan
restart System
Termiating
真的是太长了。。。。
练习25:
在GreenhouseGontrols.java中继承GreenhouseControls,增加Event内部类,用以开启、关闭喷水机。写一个新版的GreenhouseController.java以使用这些新的Event对象。
代码
package greenHouse;
public class GreenhouseNewController extends GreenHouseControls {
private boolean waterMachine = false;
public class WaterMachineOn extends Event {
public WaterMachineOn(long delayTime) {
super(delayTime);
}
@Override
public void action() {
waterMachine = true;
}
@Override
public String toString() {
return "turn on the faucet";
}
}
public class WaterMachineOff extends Event {
public WaterMachineOff(long delayTime) {
super(delayTime);
}
@Override
public void action() {
waterMachine = false;
}
@Override
public String toString() {
return "turn off the faucet";
}
}
public static void main(String[] args) {
GreenhouseNewController greenHouseController = new GreenhouseNewController();
greenHouseController.addEvent(greenHouseController.new Bell(900));
Event[] events = new Event[]{
greenHouseController.new ThermostatNight(0),
greenHouseController.new LightOn(200),
greenHouseController.new LightOff(400),
greenHouseController.new WaterOn(600),
greenHouseController.new WaterOff(800),
greenHouseController.new ThermostatDay(1400),
greenHouseController.new WaterMachineOff(3000),
greenHouseController.new WaterMachineOn(600)
};
greenHouseController.addEvent(greenHouseController.new Restart(2000, events));
if (args.length == 1) {
greenHouseController.addEvent(new GreenhouseNewController.Terminate(new Integer(args[0])));
}
greenHouseController.run();
}
}
输出
Ding
Thermostat on night setting
light is on
light is off
greenHouse water is on
greenhouse water is off
Thermostat on day setting
turn off the faucet
turn on the faucet
restart System
Termiating
练习26:
创建一个包含内部类的类,此内部类有一个非默认的构造器(需要参数的构造器)。创建另一个也绑架内部类的类,此内部继承自第一个内部类。
代码
package innerClassPackage;
public class WithinClass {
class innerClass {
void out() {
System.out.println("i am out");
}
}
}
package innerClassPackage;
public class InitWithinClass extends WithinClass.innerClass {
public InitWithinClass(WithinClass withinClass) {
withinClass.super();
}
public static void main(String[] args) {
InitWithinClass initWithinClass = new InitWithinClass(new WithinClass());
initWithinClass.out();
}
}
输出
i am out
必须要在构造器内使用enclosingClassReference.super();
xx,这章写的好辛苦,看完点个赞吧。