第10章 内部类

第10章 内部类

10.1 创建内部类

public class Parcel {

    class A{
        String f(){
            return "内部类A";
        }
    }

    // 使用内部类
    public void getMsg(A a){
        System.out.println(a.f());
    }

    // 获得内部类
    public A getA(){
        return new A();
    }
}

public class Test {
    public static void main(String[] args) {
        Parcel parcel = new Parcel();
        Parcel.A a = parcel.getA();
        parcel.getMsg(a);
    }
}

10.2 链接到外部类

内部类拥有其外围类的所有元素访问权。

迭代器案例

public interface Selector {
    // 判断是否到末尾
    boolean end();
    // 获取元素
    Object current();
    // 指向下一个
    void next();
}

public class Sequence {
    private Object[] items;
    private int next = 0;

    public Sequence(int size) {
        items = new Object[size];
    }
    // 添加对象
    public void addObject(Object o) {
        if (next < items.length) {
            items[next++] = o;
        }
    }
    // 获得迭代器
    public Selector getSelector() {
        return new MySelector();
    }

    private class MySelector implements Selector {
        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 class Test {
    public static void main(String[] args) {
        Sequence sequence = new Sequence(10);
        // 向序列中添加对象
        for (int i = 0; i < 10; i++) {
            sequence.addObject(i);
        }
        // 获得迭代器
        Selector selector = sequence.getSelector();
        while (!selector.end()){
            System.out.println(selector.current());
            selector.next();
        }
    }
}

10.3 使用.this和.new

public class Do {
    private String s;

    public Do(String s) {
        this.s = s;
    }

    public class inner {
        public Do getDo() {
            // 获得外部类对象
            return Do.this;
        }
    }

    public void f() {
        System.out.println(s);
    }
}
public class Test {
    public static void main(String[] args) {
        Do d = new Do("ding");
        // 创建内部类对象
        Do.inner inner = d.new inner();
        inner.getDo().f();
    }
}

10.4 内部类与向上转型

private内部类完全阻止了依赖类型的编码,并且隐藏了实现的细节。

public interface Contents {
    void value();
}
public class Parcel {

    private class PContents implements Contents{
        @Override
        public void value() {
            System.out.println("hello");
        }
    }

    public Contents get(){
        return new PContents();
    }
}
public class Test {
    public static void main(String[] args) {
        Parcel parcel = new Parcel();
        Contents contents = parcel.get();
        contents.value();
    }
}

10.5 在方法和作用域内的内部类

// 在方法中的内部类
public class Parcel {
    public Contents getCon(){
        class DCon implements Contents{
            @Override
            public void value() {
                System.out.println("hello");
            }
        }
        return new DCon();
    }
}

// 在作用域内的内部类
public class Parcel {
    public void f(int i){
        if (i > 10){
            class DCon implements Contents{
                @Override
                public void value() {
                    System.out.println("输入大于10");
                }
            }
            DCon dCon = new DCon();
            dCon.value();
        }
    }
}

10.6 匿名内部类

可以是继承父类或者实现接口

// 基本匿名内部类
public class Parcel {
    public Contents f(){
        Contents contents = new Contents() {
            @Override
            public void value() {
                System.out.println("基本匿名内部类");
            }
        };
        return contents;
    }
}

// 带参数构造器的匿名内部类,实质上调用的是父类的构造器
public class Do {
    protected String s;

    public Do(String s) {
        this.s = s;
    }
    
    public void e() {
        System.out.println(s);
    }
}
public class Parcel {
    public Do f(){
        Do d = new Do("ding"){
            @Override
            public void e() {
                System.out.println(s);
            }
        };
        return d;
    }
}

// 初始化成员变量,传入的参数必须是final的
public class Parcel {
    public Contents f(final String name) {
        return new Contents() {
            private String ProName = name;
            @Override
            public void value() {

            }
        };
    }
}

// 构造器效果
public class Parcel {

    public Contents getC(final String name){
        return new Contents() {
            private String proName;
            {
                if (name.contains("d")){
                    proName = name;
                }
            }
            @Override
            public void value() {
                System.out.println(proName);
            }
        };
    }
}

// 成员变量初始化也可以使用匿名内部类,同时可以使用外部类中的任何成员
public class Parcel {
    private String age = "15";
    private Contents contents = new Contents() {
        @Override
        public void value() {
            String s = age;
        }
    };
}

注意:

方法中,从外部传入匿名内部类的元素必须是final的,但是在其他情况下不是必须的,比如父类构造器参数。

10.6.1 匿名内部类实现工厂方法
public interface Service {
    void e();
    void f();
}

public interface ServiceFactory {
    Service getService();
}

public class ServiceImp1 implements Service {
    // 一般情况下,工厂对象只需要一个,所以使用静态对象
    public static ServiceFactory factory = new ServiceFactory() {
        @Override
        public Service getService() {
            return new ServiceImp1();
        }
    };

    @Override
    public void e() {
        System.out.println("1.e");
    }

    @Override
    public void f() {
        System.out.println("1.f");
    }
}

public class ServiceImp2 implements Service {
    public static ServiceFactory factory = new ServiceFactory() {
        @Override
        public Service getService() {
            return new ServiceImp2();
        }
    };

    @Override
    public void e() {
        System.out.println("2.e");
    }

    @Override
    public void f() {
        System.out.println("2.f");
    }
}

public class Test {
    public static Service exe(ServiceFactory factory){
        Service service = factory.getService();
        return service;
    }
    public static void main(String[] args) {
        Service service1 = exe(ServiceImp1.factory);
        service1.e();
        service1.f();
        Service service2 = exe(ServiceImp2.factory);
        service2.e();
        service2.f();
    }
}

/*
1.e
1.f
2.e
2.f
*/

10.7 嵌套类

嵌套类:将内部类声明成static,该内部类对象就不会和外部类对象有任何联系。

public class Parcel {

    public static class PaC implements Contents{
        @Override
        public void value() {

        }
    }
    /*
    注意:嵌套类可以在静态方法和非静态方法中new,但是普通内部类只能在非静态方法中new,换句话说,
    普通类必须依赖某个外部对象,而静态内部类不依赖具体的外部对象
    */
    public static Contents getCon(){
        return new PaC();
    }
}

public class Test {
    public static void main(String[] args) {
        Contents con = Parcel.getCon();
        // 创建静态内部类对象
         Parcel.PaC paC = new Parcel.PaC();
    }
}

接口内部类

接口内部类默认是public static的

如果希望某些代码被该接口的实现所共用,该方式是一种合适的方式

public interface Contents {
    void value();

    // 甚至可以实现外部接口
    class Dc implements Contents{

        @Override
        public void value() {
            System.out.println("hello");
        }

        public static void main(String[] args) {
            Dc dc = new Dc();
            dc.value();
        }
    }

}

public class Parcel implements Contents{
    @Override
    public void value() {
        // 直接使用接口中的内部类
        Dc dc = new Dc();
        dc.value();
    }
}

多层嵌套访问外部类成员

public class Parcel {
    
    public String f(){
        return "a";
    }
    
    public class M{
        
        public class N{
            // 无论嵌套多少层,内部总是能访问外部的成员
            private String s = f();
        }
    }
}

10.8 为什么需要内部类

最重要的因素:内部类可以独立的继承一个接口的实现,解决了多重继承问题。

实现接口的方式

public interface A {
    void f();
}

interface B{
    void e();
}
// 实现多个
class C implements A,B{
    @Override
    public void f() {
        
    }

    @Override
    public void e() {

    }
}

// 实现单个,在内部类中实现其他
class D implements A{

    @Override
    public void f() {
        
    }
    
    class E implements B{

        @Override
        public void e() {
            
        }
    }
}

继承类

public class A {
    void f(){
        
    }
}

class B{
    void e(){
        
    }
}
// 由于单继承原因,通过内部类继承的方式实现伪多继承
class C extends A{
    class D extends B{
        
    }
}

内部类其他的优势

  • 可以有多个实例,每个实例都有自己的状态信息,并与外部类独立;
  • 外部类可以有多个内部类以不同的方式实现、继承相同的接口、类;
  • 内部类创建的时刻并不依赖外部类;
10.8.1 闭包与回调

闭包: 是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。

内部类是面向对象的闭包,它不仅包含外围类对象的信息(个人理解为成员变量和方法),还拥有指向其的引用。

// 统一接口
public interface IncrementAble {
    void increment();
}

// 简单实现方式
public class Called1 implements IncrementAble {
    private int i =0;
    @Override
    public void increment() {
        i++;
        System.out.println(i);
    }
}

// 需要第二种实现方式继承的类
public class MyIncrement {
    public void increment(){
        System.out.println("基类方法");
    }
}

// 继承的类和要实现的接口方法同名,此时使用内部类就可以解决这个问题,此时也是闭包概念的运用
public class Called2 extends MyIncrement {
    private int i =0;
    @Override
    public void increment() {
        super.increment();
        i++;
        System.out.println(i);
    }

    private class Closuse implements IncrementAble{
        @Override
        public void increment() {
            Called2.this.increment();
        }
    }

    public IncrementAble getClo(){
        return new Closuse();
    }
}
public class Caller {

    private IncrementAble ia;
    // Caller需要一个实现了IncrementAble接口的对象参数,Caller可以通过它回调increment()方法
    public Caller(IncrementAble incrementAble){
        ia = incrementAble;
    }

    public void go(){
        ia.increment();
    }
}

public class Test {
    public static void main(String[] args) {
        Called1 called1 = new Called1();
        Called2 called2 = new Called2();
        Caller c1 = new Caller(called1);
        c1.go();
        Caller c2 = new Caller(called2.getClo());
        c2.go();
    }
}
10.8.2 内部类与控制框架

控制框架用来解决响应事件的需求,在GUI中,大量使用,其中包含大量的内部类。

通过模拟一个温室系统例子展示控制框架,及内部类的优越性。

/**
 * 定义要控制的事件
 * 为什么使用抽象类而不是接口?
 * 因为此处含有默认的行为(基于时间去实现)
 */
public abstract class Event {
    /**
     * 定义事件执行时间
     */
    private long eventTime;
    /**
     * 定义事件延迟执行时间
     */
    protected final long delayTime;

    public Event(long delayTime){
        this.delayTime = delayTime;
        start();
    }

    /**
     * 计算事件执行的时间
     */
    public void start(){
        eventTime = System.currentTimeMillis()+delayTime;
    }

    /**
     * 表示事件可以执行了
     */
    public boolean ready(){
        return System.currentTimeMillis() >= eventTime;
    }

    /**
     * 执行事件的方法
     */
    public abstract void action();
}

public class Controller {

    private List<Event> list = new ArrayList<>();

    /**
     * 添加事件
     * @param event
     */
    public void addEvent(Event event){
        list.add(event);
    }

    /**
     * 执行事件
     */
    public void run(){
        while (list.size()>0){
            // 注意,此处是新建了一个list对象
            for (Event event : new ArrayList<Event>(list)) {
                // 当该事件准备好时,执行
                if (event.ready()){
                    System.out.println(event);
                    event.action();
                    // 删除执行完毕的事件
                    list.remove(event);
                }
            }
        }
    }
}

/**
 * 温室系统的运作
 */
public class MyController 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";
        }
    }

    /**
     * 响铃系统
     */
    public class Bell extends Event{
        public Bell(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            // 两种方法,新建对象或者调用该对象,并重新计时
            //addEvent(new Bell(delayTime));
            addEvent(this);
            start();
        }

        @Override
        public String toString() {
            return "开始!";
        }
    }

    /**
     * 重复运行系统
     */
    public class ReStart extends Event{
        private Event[] events;

        /**
         * @param delayTime 延迟执行时间
         * @param events 重新开始的事件
         */
        public ReStart(long delayTime,Event[] events) {
            super(delayTime);
            this.events = events;
            // 创建restart对象时第一次添加对象
            for (Event event : events) {
                addEvent(event);
            }
        }

        @Override
        public void action() {
            // 重复添加对象
            for (Event event : events) {
                addEvent(event);
                event.start();
            }
            // 最后将自己添加
            addEvent(this);
            start();
        }

        @Override
        public String toString() {
            return "ReStart";
        }
    }

    /**
     * 终止运行事件
     */
    public static class Terminate extends Event{

        public Terminate(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            System.exit(0);
        }

        @Override
        public String toString() {
            return "结束";
        }
    }
}

public class Test {
    public static void main(String[] args) {
        MyController gc = new MyController();
        gc.addEvent(gc.new Bell(900));
        Event[] events = {gc.new LightOn(200),
                gc.new LightOff(800)};
        gc.addEvent(gc.new ReStart(2000, events));
        // 判断外界的输入参数,终止程序
        if (args.length == 1) {
            gc.addEvent(new MyController.Terminate(new Integer(args[0])));
        }
        gc.run();
    }
}

10.9 内部类的继承

public class WithInner extends Out{
    public WithInner(){
        super();
        System.out.println("基类构造器");
    }
    public class Inner{
        public Inner(){
            System.out.println("内部类构造器");
        }
        public void print(){
            System.out.println("hello");
        }
    }
}

public class ExcendInner extends WithInner.Inner {

    public ExcendInner(WithInner wi) {
        /*
        内部类是依附于某个对象的存在,此处相当于普通类的super();
        父类必须初始化,但是编译器并不知道怎么做,需要在这里明确指明
         */
        wi.super();
    }

    public static void main(String[] args) {
        WithInner withInner = new WithInner();
        ExcendInner excendInner = new ExcendInner(withInner);
        excendInner.print();
    }
}

10.10 内部类可以被覆盖吗

public class Egg {
    private Yolk y;

    public Egg(){
        System.out.println("new Egg");
        y = new Yolk();
    }
    protected class Yolk{
        public Yolk(){
            System.out.println("Egg.Yolk");
        }
    }

}
public class BigEgg extends Egg {
    protected class Yolk{
        public Yolk(){
            System.out.println("Big.Yolk");
        }
    }

    public static void main(String[] args) {
        new BigEgg();
    }
    /*
    new Egg
	Egg.Yolk
	可以看到,此处新建的仍然是基类的内部类,基类和子类的内部类可以认为是完全独立的存在
    */
}

// 在子类中继承内部类
public class Egg {
    private Yolk y;

    public Egg(){
        System.out.println("new Egg");
        setY(new Yolk());
    }

    public void setY(Yolk yolk){
        y = yolk;
    }
    public void g(){
        y.f();
    }
    protected class Yolk{
        public Yolk(){
            System.out.println("Egg.Yolk");
        }
        public void f(){
            System.out.println("基类方法");
        }
    }

}
public class BigEgg extends Egg {
    public BigEgg(){
        System.out.println("new BigEgg");
        setY(new Yolk());
    }
    protected class Yolk extends Egg.Yolk{
        // 此处继承内部类为什么不用调用父类的构造器?
        // 因为外部类继承了内部类基类的外部类,该外部类对象就是内部类指向的对象
        public Yolk(){
            System.out.println("Big.Yolk");
        }

        @Override
        public void f() {
            System.out.println("子类方法");
        }
    }

    public static void main(String[] args) {
        BigEgg bigEgg = new BigEgg();
        bigEgg.g();
    }
    /*
    // 初始化基类
    new Egg
    // 基类中创建内部类,内部类初始化
    Egg.Yolk
    // 初始化子类
    new BigEgg
    // 子类中创建内部类,内部类初始化基类
    Egg.Yolk
     // 子类中创建内部类,内部类初始化
    Big.Yolk
    // 调用f()(现在是重写后的方法)
    子类方法
    */
}

10.11 局部内部类

public interface Counter {
    int next();
}
public class LocalClass {
    private int count =0;

    public Counter getC1(final String name){
        class C implements Counter{
            C(){
                System.out.println(name);
            }
            @Override
            public int next() {
                return ++count;
            }
        }
        return new C();
    }

    public Counter getC2(final String name){
        return new Counter() {
            {
                System.out.println(name);
            }
            @Override
            public int next() {
                return ++count;
            }
        };
    }

    public static void main(String[] args) {
        LocalClass localClass = new LocalClass();
        Counter c1 = localClass.getC1("局部内部类");
        Counter c2 = localClass.getC2("匿名内部类");
        System.out.println(c1.next());
        System.out.println(c2.next());
    }
}

总结: 可以看到,局部内部类和匿名内部类没有什么区别,它使用的场景有两个:需要使用具名构造器,或者是需要不止一个对象。

10.12 内部类标识符

一般情况:外围类名+$+内部类名

匿名内部类:外围类名+$+数字

局部内部类:外围类名+$+数字+类名

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值