Java编程思想第十章"内部类"的10.3至10.6小节的练习题

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值