0%

内部类

为什么需要内部类

  1. 完善多重继承
  2. 闭包与回调

多继承

坏处

  1. 因为某个功能或者属性而继承许多不必要的东西
  2. 继承的多个父类,可能出现同名方法或者属性,此时就会有歧义

内部类实现多继承

虽然C++的多继承一直被诟病,但有时是真的需要多继承来完成,Java中可以通过实现多个接口或者内部类来模拟多继承

  • Eraser抽象类

    1
    2
    3
    public abstract class Eraser {
    public abstract void erase();
    }
  • Pencil抽象类

    1
    2
    3
    public abstract class Pencil {
    public abstract void wirte();
    }
  • PencilWithEraser子类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package innerClass.meaning.mutiExtends;

    /**
    * Created by lqs on 2018/5/9.
    */
    public class PencilWithEraser extends Pencil{

    private MyEraser eraser = new MyEraser();

    @Override
    public void work() {
    System.out.println("use to write");
    }


    /**
    * 继承了橡皮擦的功能
    */
    private class MyEraser extends Eraser {
    @Override
    public void work() {
    PencilWithEraser.this.eraser();
    }
    }


    private void eraser() {
    System.out.println("use to erase");
    }

    public Eraser getEraser(){ //这里返回父类抽象类类型,因为内部类(子类)是private,外部无法访问里面的方法
    return new MyEraser();
    }
    }
  • Test测试

    1
    2
    3
    4
    5
    6
    7
    public class Test {
    public static void main(String[] args) {
    PencilWithEraser pencilWithEraser = new PencilWithEraser();
    pencilWithEraser.work();//write
    pencilWithEraser.getEraser().work();//eraser
    }
    }

闭包和回调

什么叫闭包

闭包这个概念我第一次是在js这种动态语言获知的,很多语言都有闭包,简短的话来说,一个持有外部环境变量的函数就是闭包

回调

就不多解释了,A提供API给B调用,有时需要A在特定条件和时机调用B的方法。

一般使用一个库或类时,是你主动调用人家的API,这个叫Call,有的时候这样不能满足需要,需要你注册(注入)你自己的程序(比如一个对象),然后让人家在合适的时候来调用你,这叫Callback。

  • 主体

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    //接口
    public interface Incrementable {
    void increment();
    }

    // Very simple to just implement the interface
    class Callee1 implements Incrementable {
    private int i = 0;

    public void increment() {
    i++;
    System.out.println(i);
    }
    }


    class MyIncrement {
    public void increment() {
    System.out.println("Other operation");
    }

    static void f(MyIncrement mi) {
    mi.increment();
    }
    }


    // If your class must implement increment() in
    // some other way, you must use an inner class:
    //既想实现接口又想继承,然而接口和父类都有相同名称的方法
    class Callee2 extends MyIncrement {
    private int i = 0;

    public void increment() {
    super.increment();
    i++;
    System.out.println(i);
    }

    //内部类实现接口
    private class Closure implements Incrementable {
    //实现方法在外部类里
    public void increment() {
    // Specify outer-class method, otherwise
    // you'd get an infinite recursion
    Callee2.this.increment();
    }
    }

    //返回一个内部类的引用
    Incrementable getCallbackReference() {
    return new Closure();
    }
    }

    //回调
    class Caller {
    //持有回调的引用
    private Incrementable callbackReference;

    Caller(Incrementable cbh) {
    callbackReference = cbh;
    }

    void go() {
    callbackReference.increment();
    }
    }
  • 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class Callbacks {
    public static void main(String[] args) {
    Callee1 c1 = new Callee1();
    Callee2 c2 = new Callee2();
    MyIncrement.f(c2);
    System.out.println("\n");
    Caller caller1 = new Caller(c1);
    Caller caller2 = new Caller(c2.getCallbackReference());
    caller1.go();
    caller1.go();
    System.out.println("caller2");
    caller2.go();
    caller2.go();
    }
    }

内部类是面向对象的闭包,因为它不仅包含创建内部类的作用域的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。