回调模式的概念
回调模式是指:如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。
假设已存在AnonymousInterface接口,在实现类AnonymousInterfaceTest中已有test()方法,该方法把接口类型的引用当形参传递进方法体中,以调用show方法;现在该如何调用静态方法test()?
很简单在main方法中使用类名.的方式调用静态方法show(),这时候show方法中需要传递接口类型的形参,我们直接建立AnonymousInterface的实现类,重写接口中的抽象方法(因为接口是不能被实例化的,接口中的抽象类是需要重写后才能使用),实现类AnonymousInterfaceImpl 实现接口并且把实现类当作形参传递进show方法中。
package com.lagou.task10; public interface AnonymousInterface { public abstract void show(); }
package com.lagou.task10; public class AnonymousInterfaceImpl implements AnonymousInterface { @Override public void show() { System.out.println("重写AnonymouInterface的接口"); } }
package com.lagou.task10; public class AnonymousInterfaceTest { public static void test(AnonymousInterface ai){ ai.show(); } public static void main(String[] args) { AnonymousInterfaceTest.test(new AnonymousInterfaceImpl()); } }
在我们刚刚编写的代码中,我为了能够让test()这个方法正常地调用,我单独为这个形参的接口类型提供了一个实现类;但是如果这个方法只需要被调用一次,为了调用这个方法单独写一个类让他加载到内存中让它一直占着方法区是不是有点杀鸡用牛刀的意思?因为我们比较写完一个类之后我们就让他加载到内存中而且它会一直占着内存空间,那么有没有更好的办法呢?如果说我们要使用接口类型的引用作为形参时,我们调用的时候这个方法只被调用一次时,我们有没有更加简便的方法而且我们要做到调用一次它所占的内存空间就随之释放的呢?这个时候我们就要用到另外一个东西:叫做匿名内部类
当接口/类类型的引用作为方法的形参时,实参的传递方式有两种:
自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递;
使用上述匿名内部类的语法格式得到接口/类类型的引用即可;
匿名内部类的语法格式(重点)
接口/父类类型 引用变量名 = new 接口/父类类型(){方法的重写};
这种写法和上述的写法有什么优势?优势在于我new完对象这个类的价值就不存在了,就可以销毁他的存储空间了。
package com.lagou.task10; public class AnonymousInterfaceTest { // 假设已有下面的方法,请问如何调用下面的方法? // AnonymousInterface ai = new AnonymousInterfaceImpl(); // 接口类型的引用指向实现类型的对象,形成了多态 public static void test(AnonymousInterface ai){ // 编译阶段调用父类版本,运行调用实现类重写的版本 ai.show(); } public static void main(String[] args) {// 使用匿名内部类的语法格式来得到接口类型的引用,格式为:接口/父类类型 引用变量名 = new 接口/父类类型(){方法的重写;} AnonymousInterface anonymousInterface = new AnonymousInterface() { @Override public void show() { System.out.println("匿名内部类的重写!"); } }; AnonymousInterfaceTest.test(anonymousInterface); } }
从java8开始提出新特性Lamda表达式可以简化上述代码,格式为:
(参数列表)-> {方法体}
AnonymousInterface anonymousInterface = () -> System.out.println("匿名内部类的重写!");
AnonymousInterfaceTest.test(anonymousInterface);