10.3 使用.this与.new
在内部类中如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟.this。
练习题4:在Sequence.SequenceSelector类中增加一个方法,它可以生成对外部类Sequence的引用。
代码如下:
public Sequence getSequence() {
return Sequence.this;
}
要想创建内部类的对象,可以用外部类的对象后面紧跟.new加上内部类的类名来创建。
练习题5:创建一个包含内部类的类,在另一个独立的类中,创建此内部类的实例。
代码如下:
public class Input {
/* 假设在html中有多个input的时候,每个input有一个唯一标识,使用id模拟唯一标识 */
private static int idGenerator = 0;
private final int id = ++idGenerator;
/* 模拟input的属性集合 */
private Attribute attr;
public class Attribute {
private String id;
private String type;
public Attribute(String id, String type) {
this.id = id;
this.type = type;
// 将特定属性和特定input建立关联,用于实验Input.this可以获取外部类引用,
// 而this是内部类Attribute的实例引用
Input.this.setAttr(this);
System.out.println("这个输入框的id为:" + id + ",其类型是:" + type);
}
@Override
public String toString() {
return "Attribute [id=" + id + ", type=" + type + "]";
}
}
public void setAttr(Attribute attr) {
this.attr = attr;
}
@Override
public String toString() {
return "Input [id=" + id + ", attr=" + attr + "]";
}
}
public class Html {
public static void main(String[] args) {
Input input = new Input();
Input.Attribute attr = input.new Attribute("name", "text");
System.out.println(input);
}
}
10.4 内部类与向上转型
当将内部类向上转型为基类或一个接口时,可以通过设置内部类的访问修饰符(private、package等),使其能够完全不可见,并且不可用。而我们所得到的引用只是指向基类或接口的引用,所以能够很方便地隐藏实现细节。
练习题6:在第一个包中创建一个至少有一个方法的接口。然后在第二个包内创建一个类,在其中增加一个protected的内部类以实现那个接口。在第三个包中,继承这个类,并在一个方法中返回该protected内部类的对象,在返回的时候向上转型为第一个包中的接口的类型。
代码如下:
package com.wang.test.inner.inter;
public interface Action {
void eat();
void run();
}
package com.wang.test.inner.one;
import com.wang.test.inner.inter.Action;
public class Dog {
protected class DogAction implements Action {
public DogAction() {
}
@Override
public void eat() {
System.out.println("一般的狗喜欢吃肉骨头");
}
@Override
public void run() {
System.out.println("一般的狗喜欢奔跑");
}
}
}
package com.wang.test.inner.two;
import com.wang.test.inner.inter.Action;
import com.wang.test.inner.one.Dog;
public class Husky extends Dog {
class HuskyAction extends DogAction {
@Override
public void eat() {
System.out.println("哈士奇更喜欢吃苦瓜,嘎嘣脆,鸡肉味。");
}
@Override
public void run() {
System.out.println("哈士奇更喜欢奔跑的时候用脸刹车。");
}
}
public Action getHuskyAction() {
return new HuskyAction();
}
public Action getDogAction() {
// DogAction是Dog中的protected的成员,因此能被其子类Husky访问
return new DogAction();
}
}
练习题7:创建一个含有private域和private方法的类。创建一个内部类,它有一个方法可用来修改外围类的域,并调用外围类的方法。在外围类的另一个方法中,创建此内部类的对象,并调用它的方法,然后说明对外围类对象的影响。
代码如下:
interface Changeable {
void change();
}
public class Select {
private String id;
private String clazz;
class OnChange implements Changeable {
private String id;
private String clazz;
public OnChange(String id, String clazz) {
this.id = id;
this.clazz = clazz;
}
@Override
public void change() {
Select.this.id = id;
Select.this.clazz = clazz;
Select.this.desc();
}
}
private void desc() {
System.out.println("<select id='" + id + "' class='" + clazz + "'></select>");
}
public void change(String id, String clazz) {
new OnChange(id, clazz).change();
}
public static void main(String[] args) {
// 由于没有提供setter方法,因此select不能直接设置id和clazz,但是可以通过其内部类
// OnChange的change()方法来设置id和clazz。
Select select = new Select();
select.change("roles", "select2");
}
}
练习题8:确定外部类是否可以访问其内部类的private元素。
答:可以。
代码如下:
public class Select {
private AttrSet attrSet;
class AttrSet {
private String id;
private String clazz;
private void set(String id, String clazz) {
this.id = id;
this.clazz = clazz;
Select.this.attrSet = this;
}
private void show() {
Select.this.desc();
}
}
private void desc() {
System.out.println("<select id='" + attrSet.id + "' class='" + attrSet.clazz + "'></select>");
}
public AttrSet getAttrSet() {
return new AttrSet();
}
public static void main(String[] args) {
Select select = new Select();
Select.AttrSet attrSet = select.getAttrSet();
// 调用内部类attrSet私有方法
attrSet.set("emps", "select2");
attrSet.show();
// 设置内部类attrSet私有域
attrSet.id = "depts";
attrSet.show();
}
}
运行结果:
<select id='emps' class='select2'></select>
<select id='depts' class='select2'></select>
10.5 在方法和作用域内的内部类
可以在一个方法里或在任意的作用域内(if、for中等)定义内部类,而在方法的作用域内定义的类被称作局部内部类。这样做的好处如下:
①、实现了某接口,可以直接创建并返回对其的引用。
②、在解决一个复杂问题的时候,需要创建一个辅助类,但是又不想该类被公用。
练习题9:创建一个至少有一个方法的接口。在某个方法内定义一个内部类以实现此接口,这个方法返回对此接口的引用。
代码如下:
public interface Mode{
void start();
void run();
}
public class AudiCar {
public Mode changeMode() {
class SportMode implements Mode {
@Override
public void start() {
System.out.println("开启运动模式");
}
@Override
public void run() {
System.out.println("在运动模式下运行果然加速更快");
}
}
return new SportMode();
}
public static void main(String[] args) {
AudiCar car = new AudiCar();
car.changeMode().start();
car.changeMode().run();
}
}
练习题10:重复前一个练习但将内部类定义在某个方法的一个作用域内。
代码如下:
public class AudiCar {
public Mode changeMode(int modeType) {
if (modeType == 1) {
class SportMode implements Mode {
@Override
public void start() {
System.out.println("开启运动模式");
}
@Override
public void run() {
System.out.println("在运动模式下运行果然加速更快");
}
}
return new SportMode();
}
// return new SportMode(); 作用域外,无法识别该类型,即不能用
return new Mode() {
@Override
public void start() {
System.out.println("开启默认模式");
}
@Override
public void run() {
System.out.println("默认模式下没有运动模式下加速快");
}
};
}
public static void main(String[] args) {
AudiCar car = new AudiCar();
// 运动模式
car.changeMode(1).start();
car.changeMode(1).run();
// 默认模式
car.changeMode(0).start();
car.changeMode(0).run();
}
}
练习题11:创建一个private内部类,让它实现一个public接口。写一个方法,它返回一个指向此private内部类的实例的引用,并将此引用向上转型为该接口类型。通过尝试向下转型,说明此内部类被完全隐藏了。
代码实现:
public class MuranoCar {
private class SnowMode implements Mode {
@Override
public void start() {
System.out.println("楼兰汽车开启雪地模式");
}
@Override
public void run() {
System.out.println("在雪地上果然很稳健");
}
}
public Mode getMode() {
return new SnowMode();
}
}
class Test {
public static void main(String[] args) {
MuranoCar car = new MuranoCar();
Mode mode = car.getMode();
mode.start();
mode.run();
// SnowMode snowMode = (SnowMode)mode; 无法识别SnowMode类型
}
}
10.6 匿名内部类
练习题12:重复练习题7,这次使用匿名内部类。
代码如下:
interface Changeable {
void change();
}
public class Select {
private String id;
private String clazz;
private void desc() {
System.out.println("<select id='" + id + "' class='" + clazz + "'></select>");
}
public void change(String id, String clazz) {
new Changeable() {
@Override
public void change() {
Select.this.id = id;
Select.this.clazz = clazz;
Select.this.desc();
}
}.change();
}
public static void main(String[] args) {
Select select = new Select();
select.change("roles", "select2");
}
}
练习题13:重复练习题9,这次使用匿名内部类。
代码如下:
public class AudiCar {
public Mode sportMode() {
return new Mode() {
@Override
public void start() {
System.out.println("开启运动模式");
}
@Override
public void run() {
System.out.println("在运动模式下运行果然加速更快");
}
};
}
public static void main(String[] args) {
AudiCar car = new AudiCar();
// 运动模式
car.sportMode().start();
car.sportMode().run();
}
}
练习题14:修改interfaces/HorrorShow.java,用匿名类实现DangerousMonster和Vampire。
代码如下:
// 恶魔
interface Monster {
// 恐吓
void menace();
}
interface DangerousMonster extends Monster {
void destroy();
}
// 致命
interface Lethal {
void kill();
}
interface Vampire extends DangerousMonster, Lethal {
void drinkBlood();
}
// 恐怖秀
public class HorrorShow {
static void u(Monster b) {
b.menace();
}
static void v(DangerousMonster d) {
d.menace();
d.destroy();
}
static void w(Lethal l) {
l.kill();
}
DangerousMonster getMonster() {
return new DangerousMonster() {
@Override
public void menace() {
System.out.println("狼人很可怕");
}
@Override
public void destroy() {
System.out.println("喜欢搞破坏");
}
};
}
Vampire getVampire() {
return new Vampire() {
@Override
public void kill() {
System.out.println("吸血鬼会杀人");
}
@Override
public void menace() {
System.out.println("它们很可怕");
}
@Override
public void destroy() {
System.out.println("总是搞破坏");
}
@Override
public void drinkBlood() {
System.out.println("喜欢喝血");
}
};
}
public static void main(String[] args) {
HorrorShow hs = new HorrorShow();
// 狼人
DangerousMonster werewolf = hs.getMonster();
u(werewolf);
v(werewolf);
// 吸血鬼
Vampire vampire = hs.getVampire();
u(vampire);
v(vampire);
w(vampire);
}
}
练习题15:创建一个类,它有非默认的构造器,并且没有默认构造器。创建第二个类,它包含一个方法,能够返回对第一个类的对象的引用。通过写一个继承自第一个类的匿名内部类,来创建一个返回对象。
代码如下:
class Car {
public Car(String brand, int capacity) {
}
void desc() {
}
}
public class CarMarket {
Car getCar(String brand, int capacity) {
// 使用带参数的构造器来创建匿名内部类
return new Car(brand, capacity) {
@Override
void desc() {
System.out.println("这辆车是:" + brand + ",核载人数:" + capacity + "人");
}
};
}
public static void main(String[] args) {
CarMarket market = new CarMarket();
Car car = market.getCar("奥迪A4", 5);
car.desc();
}
}
练习题16:修改第9章中练习题18的解决方案,让他使用匿名内部类。
代码如下:
public interface Cycle {
void cycle();
}
public interface CycleFactory {
Cycle getCycle();
}
class Unicycle implements Cycle {
private Unicycle() {
}
@Override
public void cycle() {
System.out.println("骑单轮脚踏车很有趣,但是很累。");
}
// 匿名内部工厂类
public static final CycleFactory factory = new CycleFactory() {
@Override
public Cycle getCycle() {
return new Unicycle();
}
};
}
class Bicycle implements Cycle {
private Bicycle() {
}
@Override
public void cycle() {
System.out.println("练习骑自行车。");
}
// 匿名内部工厂类
public static final CycleFactory factory = new CycleFactory() {
@Override
public Cycle getCycle() {
return new Bicycle();
}
};
}
class Tricycle implements Cycle {
private Tricycle() {
}
@Override
public void cycle() {
System.out.println("三轮车果然骑起来很稳。");
}
// 匿名内部工厂类
public static final CycleFactory factory = new CycleFactory() {
@Override
public Cycle getCycle() {
return new Tricycle();
}
};
}
运行代码如下:
public class Test {
public static void cycle(CycleFactory factory) {
Cycle cycle = factory.getCycle();
cycle.cycle();
}
public static void main(String[] args) {
// 使用不同的工厂来切换不同的产品实现
cycle(Unicycle.factory);
cycle(Bicycle.factory);
cycle(Tricycle.factory);
}
}
练习题17:修改第9章中练习题19的解决方案,让它使用匿名内部类。
代码如下:
public interface Game {
void play();
}
public interface GameFactory {
Game getGame();
}
public class Dice implements Game {
private Random random = new Random();
private Dice() { // 禁止通过构造器创建实例
}
@Override
public void play() {
int val = random.nextInt(6) + 1;
switch (val) {
case 1:
System.out.println("⚀");
break;
case 2:
System.out.println("⚁");
break;
case 3:
System.out.println("⚂");
break;
case 4:
System.out.println("⚃");
break;
case 5:
System.out.println("⚄");
break;
case 6:
System.out.println("⚅");
break;
}
}
// 匿名内部工厂类
public static final GameFactory factory = new GameFactory() {
@Override
public Game getGame() {
return new Dice();
}
};
}
public class TossACoin implements Game {
private Random random = new Random();
private TossACoin() { // 禁止通过构造器创建实例
}
@Override
public void play() {
int val = random.nextInt(2);
switch (val) {
case 0:
System.out.println("花");
break;
case 1:
System.out.println("字");
break;
}
}
// 匿名内部工厂类
public static final GameFactory factory = new GameFactory() {
@Override
public Game getGame() {
return new TossACoin();
}
};
}
运行代码如下:
public class Test {
public static void play(GameFactory factory) {
for (int i = 0; i < 2; i++) {
factory.getGame().play();
}
}
public static void main(String[] args) {
play(TossACoin.factory);
play(Dice.factory);
}
}