内部匿名类在一些Java书籍中写得非常抽象,其实这东西,如果单独拿出来讲的话,也确实很难讲得通,我本来以为如此抽象的概念,并没有什么用。万万没想到到是,这东西在安卓编程的监听器中使用得尤其之多。匿名内部类根本一点都不难,大家一直在用,却一直都不知道自己在用,被问到这个概念就懵了。如果你用过jQuery,你一定见过如下的结构:
$("#组件id").click(function(){ //要做的事情 });
这里组件id被点击的监听器function(){}就是一个匿名内部函数。
好吧,如果你用过jQuery,那么,我将会以如下的一个小例子来说明这个问题。
定义一个定时器,每1秒把i自加。再定义一个线程,每5秒检查i是否超过3,如果i超过3,则把定时器停止,同时自己自然死亡。
定时器的使用在《【Java】利用Timer与TimerTask定时执行任务》(点击打开链接)已经说过了,线程的使用也在《【Java】线程并发、互斥与同步》(点击打开链接)讨论过了。
本来如果要在Java中使用定时器,线程要写较长的代码的,先new一个定时器或者线程,然后再开一个继承定时器、线程抽象接口的类,重写里面的方法。
但是,如果你使用了匿名内部类,上图的程序的代码,则演变成这样:
import java.util.*; public class timerTheardTest { private static int i = 0; private static Timer timer; public static void main(String[] args) { timer = new Timer(); timer.schedule(new TimerTask() { @Override // 如果这里出现int i=2;这个i将会作用于这个匿名内部类的所有方法 // 上面的private static int i=0;失效 // 请注意,此时出现int i=2,是没有语法错误的! public void run() { System.out.println(i++); } }, 0, 1000); new Thread(new Runnable() { @Override //在Runnable中,如果要让线程自己一直跑下去,必须自己定义while结构 //如果这个run()方法读完了,则整个线程自然死亡 public void run() { //定义一个线程中止标志 boolean isContinue = true; while (isContinue) { try { Thread.sleep(5000);//Java中线程的休眠,必须在try-catch结构中 } catch (InterruptedException e) { e.printStackTrace(); } if (i > 3) { timer.cancel();//中止定时器 isContinue = false;//跳出这个死循环,让线程自然死亡 } } } }).start();//默认线程不启动,必须自己start() } }
程序先定义两个覆盖与整个主类的全局变量,一个自增的i,一个定时器timer。自增i要被定时器、线程同时操作,所以成为全局变量是一定的。有人可能疑惑为何定时器timer也要是全局变量。那是因为在线程中有中止定时器的方法。如果你在主函数中才定义定时器,其作用范围无法覆盖到线程中Runnable这个匿名内部类。
之后,非常清晰地可以看到,本来定时器第一个参数必须填上一个继承TimerTask的类,为了配合,我们原本要又要开一个类,同时为这个类命名,再放到这里,但是由于使用了匿名内部类的出现,现在可以直接重现。线程也是如此。这里非常想jQuery、ExtJs的Javascript前端框架的结构。安卓的组件监听器其实也在大量使用匿名内部类。
其实,以前的在《【Java】Collections中sort方法Comparator的重写》(点击打开链接)的Java程序我也使用过匿名内部类,只是自己没有注意到这个概念。