Java内部类(2): 用法和回调

本文探讨了Java内部类的使用和回调机制。内部类提供了进入外部类的窗口,允许外部类实现多个接口而不会相互影响。回调是层间协作的方式,Java中通过接口和内部类实现回调。通过例子解释了如何利用内部类实现接口,以及回调的两种形式:外部回调和自身回调。

为什么需要内部类

一般来说,内部类继承自某个类或实现了某个接口,内部类代码操作创建它的外部类的对象,可以说,内部类提供了某种进入外部类的窗口,而且内部类自己本身实现了有效的代码隐藏。
内部类必须要回答的一个问题是:如果只是需要一个接口的引用,为什么外部类不直接实现接口呢。答案是:如果这能满足需求,就应该这么做!那么内部类实现一个接口于外部类实现这个接口有什么区别呢?答案是:后者并不总能享受接口带来的便利,有时候需要接口的实现。使用内部类最吸引人的地方在于:
外部类可以有多个内部类,每个内部类都能够独自实现一个接口(继承一个类),且无论外围类是否实现该接口(继承该类)都不会对内部类产生影响。

  • 我们考虑这样一种情况,在一个类中需要以某种方式实现两个接口A和B。这两个接口相互独立,彼此直接没有任何联系。那么有两种方式:

    1. 直接实现两个接口
    2. 该类实现接口A,另外构建一个内部类实现接口B
      一般情况下两种方式都可以,但对于第二种方式来说,它把两个接口的实现完全分离,并且可以隐藏B接口实现的细节。
      拿HashMap举例,就是通过内部类来实现Iterator接口的,既实现了hashmap的遍历功能,又保证了得到的遍历器能够访问原来的map对象并且对外部来说完全隐藏了遍历器的实现细节。如果现在需要hashmap实现另一个反向遍历接口ReIterator,那么只需要再定义一个内部类实现反向遍历接口,通过方法返回内部类实例就可以,并不需要修改外部类的实现接口。

    另一种情况:如果好巧不巧的,A、B两个接口有一个相同的方法(虽然方法名相同,但完全独立,是两个互不关联的方法),那么第一种方式就不可行了,因为你只能在类中定义一个该方法,无法区分属于哪个接口。

  • 另外一点:可以定义多个内部类,并且这些内部类相互独立。考虑这样一种情况,在一个类中需要以某种方式实现多个接口(5个以上并且每个接口的方法很多)那么,如果直接实现这些接口,那么类中的方法数量将会很多,类会变得很庞大,这也不符合代码分离的理念。
    从某种程度上来说,内部类完善了java的多继承

  • 在单个外部类中,可以让多个内部类以不同的方式实现同一个接口或继承同一个类。就像HashMap,我们可以以多种方式实现遍历操作。

内部类与回调

回调用于层间协作。例如一个驱动,是一个地层。但有数据传给它时,它不仅要处理自己本层的工作,还要进行回调,将数据传给它的上层供上层处理。
回调跟API有点相似,都是跨层级调用的。不过与API不同的是,API是下层提供给上层去调用的,那么上层主动去调用下层API,这叫Call,上层是知道所调用的下层方法的。但回调不同,回调是上层提供给下层去调用的,而且具体方法下层是不知道的,下层只知道自己需要在某些条件下调用这个方法。上层向下层注入自己的程序(比如一个对象),然后下层通过这段程序(这个对象)来反过来调用上层的方法,这叫回调。

而Java的回调呢,就是通过接口和内部类来实现的。通常是别人提供一个接口,我用内部类实现这个接口并将内部类的一个实例注入到(传递给)别人的程序,别人的程序再通过我传入的示例来调用方法。
举例说明:
//

/** ICallBack接口和Print类就好比是别人提供的程序 **/
//接口类
public interface ICallBack {
    public void execute();
}


public class Printer {
    ICallBack icb;
    public Printer(ICallBack icb){
        this.icb = icb;
    }

    //提供给外部去调用的。即提供一个接口,我不去具体实现它,由外部程序来实现。再在想要的时候去回调外部的方法。我没有实现接口,但我拥有一个是实现了接口的外部对象,我通过外部对象去调用外部的方法。
    public void print(){
        System.out.println("print start ========");//固定部分
        icb.execute(); //抽象部分,由外界去实现
        System.out.println("print end ========");//固定部分
    }
}


/PrintHandle相当于外部类
public class PrintHandle {
    public void printf(){
        System.out.println("printHandle print");
    }

    public void go(){//创建了一个匿名类对象并传递给Printer,通过内部类Printer也可以调用我的printf()方法了,这叫回调
        Printer print = new Printer(new ICallBack() {
            @Override
            public void execute() {
                printf();
            }
        });
        print.print();
    }
    public static void main(String[] args) {
        PrintHandle printHandle = new PrintHandle();
        printHandle.go();
    }

}

另外再写一个测试方法运行时间的类

public class TestTime {
    public Long getTime(ICallBack icb){
        long start = System.currentTimeMillis();
        icb.execute();
        long end = System.currentTimeMillis();
        return end-start;
    }
}

//现在我要测试运行一遍test()方法需要多长时间
public class TestTimeMain {
    public void test() {//需要测试的方法
        List<Map<String,String>> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++){
            HashMap map = new HashMap<String,String>();
            list.add(map);
        }
    }

    public static void main(String[] args) {
        TestTimeMain main = new TestTimeMain();
        TestTime testTime = new TestTime();
//测试test()方法运行的时间,只要将这个方法放到匿名内部类的execute()里面就可以了
        long time = testTime.getTime(new ICallBack() {
            @Override
            public void execute() {
                main.test();
            }
        });
        System.out.println(time);
    }
}

回调的另一种方式:我称之为自身回调。
有两个接口worker(工人)和programmer(程序员),这两个接口都有一个work()方法,现有一个员工,要求它以某种方式实现这两个接口。这只能通过内部类来实现

Interface Worker{
    void work();
}

Interface Programmer{
    void work();
}

class Employee implements Worker{
    public void work(){//作为工人在工作
        System.out.println("worker is working");
    }

    public void code(){//作为程序员在编程
        System.out.println("programmer is programming");
    }
    class Clousure implements Programmer{
        public void work(){
            code();
        }
    }

    private class Clousure implements Programmer{
        public void work(){
            code();
        }
    }

    public Programmer getCallBack(){
        return new Clousure();
    }

    public static void main(String[] args) {
        Employee employee = new Employee();
        employee.work();
        employee.getCallBack().work();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值