[TOC]

概述

可以将一个类的定义放到另一类的定义的内部,这就是内部类

为什么需要内部类

一般来说,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。所以可以认为内部类提供了某种进入其外围类的窗口。

内部类必须要回答的一个问题是:如果需要一个对接口的引用,为什么部通过外围类实现那个接口呢?答案是:“如果这能满足需求,那么就应该这样做。” 那么内部类实现一个接口和外围类实现这个接口有什么区别吗?答案是:后者不是总能享用到接口带来的方便,有时需要用到接口的实现。所有,使用内部类最吸引人的原因是:

每个内部类都能独立的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对内部类都没有影响

一种隐藏和组织代码的模式

interface Contents {
    int value();
}

interface Destination {
    String readLabel();
}
class Goods {
    private class Content implements Contents {
        private int i = 11;
        @Override
        public int value() {
            return i;
        }
    }
    protected class GDestination implements Destination {
        private String label;
        private GDestination(String whereTo) {
            label = whereTo;
        }
        @Override
        public String readLabel() {
            return label;
        }
    }
    public Destination dest(String s) {
        return new GDestination(s);
    }
    public Contents cont() {
        return new Content();
    }
}

public class MainTest {

    public static void main(String[] args) {
        Goods p = new Goods();
        Contents c = p.cont();
        System.out.println(c.value());
        Destination d = p.dest("Beijing");
        System.out.println(d.readLabel());
    }
}
/* Output:
11
Beijing
 *///:~

匿名内部类

匿名内部类没有构造器的行为(因为没有类名),但能够通过实例初始化,达到构造行为

interface Contents {
    int value();
}

interface Destination {
    String readLabel();
}

abstract class Destination2 {
    Destination2(String s){
        System.out.println("Constructor s=" + s);
    }
    abstract String readLabel();
}

class Goods3 {
    public Contents cont() {
        // 匿名内部类
        return new Contents() {
            private int i = 11;
            @Override
            public int value() {
                return i;
            }
        };
    }

    public Destination dest(String s) {
        // 匿名内部类使用参数,外围必须是final的
        // String dest 不是final 也ok(Java8) ?
        return new Destination(){
            private String label = s;
            @Override
            public String readLabel(){
                return label;
            }
        };
    }

    public static Destination2 dest2(String dest) {
        return new Destination2(dest){
            @Override
            public String readLabel(){
                return dest;
            }
        };
    }
}

public class MainTest {

    public static void main(String[] args) {
        Goods3 p = new Goods3();
        Contents c = p.cont();
        System.out.println(c.value());
        Destination d = p.dest("shanghai");
        System.out.println(d.readLabel());
        Destination2 d2 = Goods3.dest2("beijing");
        System.out.println(d2.readLabel());
    }
}
/* Output:
11
shanghai
Constructor s=beijing
beijing
 *///:~

闭包和回调

闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息用来创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。

回调(callback), 通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。

简单来说,就是我调用你的函数,你调用我的函数。正规一点的说法就是类A的a()函数调用类B的b()函数,当类B的b()函数的执行时又去调用类A里的函数。是一种双向的调用方式。一般情况下,回调分两种,分别是同步回调和异步回调。

同步回调

一种双向调用模式,被调用方在函数被调用时也会调用对方的函数。

参考: 作者:Bro__超 地址:https://www.cnblogs.com/heshuchao/p/5376298.html

class Calculator
{
    public int add(int a, int b)
    {
        return a + b;
    }
}

class SuperCalculator
{
    public void add(int a, int b, Student xiaoming)
    {
        int result = a + b;
        xiaoming.fillBlank(a, b, result);
    }
}

class Student
{
    private String name = null;

    public Student(String name)
    {
        // TODO Auto-generated constructor stub
        this.name = name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    @SuppressWarnings("unused")
    private int calcADD(int a, int b)
    {
        return a + b;
    }

//    public void fillBlank(int a, int b)
//    {
//        int result = calcADD(a, b);
//        System.out.println(name + "心算:" + a + " + " + b + " = " + result);
//    }

//    private int useCalculator(int a, int b)
//    {
//        return new Calculator().add(a, b);
//    }
//
//    public void fillBlank(int a, int b)
//    {
//        int result = useCalculator(a, b);
//        System.out.println(name + "使用计算器:" + a + " + " + b + " = " + result);
//    }

    public void callHelp(int a, int b)
    {
        new SuperCalculator().add(a, b, this);
    }

    // 类似回调函数
    public void fillBlank(int a, int b, int result)
    {
        System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
    }
}

public class MainTest {

    public static void main(String[] args) {
        int a = 1;
        int b = 1;
        Student s = new Student("小明");
        s.callHelp(a, b);
    }
}

Student调用了SuperCalculatoradd方法, add方法在执行的时候,反过来调用了Studdent的fillBlank方法

异步回调

一种类似消息或事件的机制,被调用方在函数在收到某种讯息或发生某种事件时,才去调用对方的函数,即通过异步消息进行通知。简单来说,类A的a()函数调用类B的b()函数,但是b()函数很耗时,不确定什么时候执行完毕,如果是同步调用的话会等b()执行完成后才往下执行回调类A中的函数,如果是异步回调的话调用了b()函数,虽然b()函数没有执行完,但仍然继续往下执行,为了完成这点,就需要另开一个线程了。

参考: 作者:O水冰O 来源:CSDN 原文:https://blog.csdn.net/o15277012330o/article/details/79271385

interface doJob {
    void fillBlank(int a, int b, int result);
}

class SuperCalculator {
    public void add(int a, int b, doJob  customer) {
        int result = a + b;

        //让线程等待3秒
        try {
            Thread.sleep(3 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        customer.fillBlank(a, b, result);
    }
}

class Student {
    private String name = null;

    public Student(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public class DoHomeWork implements doJob {

        @Override
        public void fillBlank(int a, int b, int result) {
            System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result);
        }

    }

    public void callHelp (int a, int b) {
        //开启另一个子线程
        new Thread(new Runnable() {
            @Override
            public void run(){
                new SuperCalculator().add(a, b, new DoHomeWork());
            }
        }).start();

    }
}

class Seller {
    private String name = null;

    public Seller(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public class DoHomeWork implements doJob {

        @Override
        public void fillBlank(int a, int b, int result)
        {
            System.out.println(name + "求助小红算账:" + a + " + " + b + " = " + result + "元");
        }

    }

    public void callHelp (int a, int b) {
        new SuperCalculator().add(a, b, new DoHomeWork());
    }
}


public class MainTest {

    public static void main(String[] args) {
        int a = 56;
        int b = 31;
        int c = 26497;
        int d = 11256;
        Student s1 = new Student("小明");
        Seller s2 = new Seller("老婆婆");

        s1.callHelp(a, b);
        System.out.println("/========================1/");
        s2.callHelp(c, d);
        System.out.println("/========================2/");

    }
}
/* output, 其中一次的输出如下, 小明的执行耗时,导致回调是迟输出的
/========================1/
老婆婆求助小红算账:26497 + 11256 = 37753元
小明求助小红计算:56 + 31 = 87
/========================2/
 */

/* output, 其中一次的输出如下, 小明的执行耗时,导致回调是迟输出的
/========================1/
小明求助小红计算:56 + 31 = 87
老婆婆求助小红算账:26497 + 11256 = 37753元
/========================2/
 */

事件驱动系统

内部类标识符

每个类都会产生.class文件

内部类: 外围类名字 + $ + 内部类但名字

Contents.class
Destination.class
Destination2.class
Goods3$1.class
Goods3$2.class
Goods3$3.class
Goods3.class

Copyright @doctording all right reserved,powered by Gitbook该文件修改时间: 2020-08-22 10:40:55

results matching ""

    No results matching ""