`
unique5945
  • 浏览: 131880 次
  • 来自: 杭州
社区版块
存档分类
最新评论

回调和内部类

    博客分类:
  • JAVA
阅读更多
以下是我在学习JAVA.IO时看到的三段代码。第一段代码用到了策略模式,用了回调方法。
在用回调时,往往可以用匿名内部类来简化代码,这就是第二段代码。但注意如果内部类需要用域外参数的话,那个参数必须为final的。
第三段代码是在第二段的基础上的再次简化,这里也涉及到域外参数必须是final的问题,一定切忌!

总结:
这类问题的特点:
1)像list(FilenameFilter filter)它会用到filter,这个传入参数FilenameFilter往往是个接口
2)接口定义了几个方法,如这里的accept(),而list用到FilenameFilter的目的就是为了调用它的accept()
3)要自己写的accept()就是所谓的回调方法(callback)
解决的方法有:
1)自己写一个接口的实现类,老老实实把这个实现类当参数传进去
2)把这个实现类写成匿名内部类,把这个内部类传进去当参数。具体方法参照下文中第二、三段程序
注意事项:
用匿名内部类来创建专门供特定问题用的,一次性的类,这种方法有利有弊
1)优点:它能把解决某个问题的代码全都集中到一个地方
2)会使代码的可读性变差,要慎重。

具体文章如下:

目录列表器
假设你想看看这个目录。有两个办法。一是不带参数调用list( )。它返回的是File对象所含内容的完整清单。但是,如果你要的是一个"限制性列表(restricted list)"的话 —— 比方说,你想看看所有扩展名为.java的文件 —— 那么你就得使用"目录过滤器"了。这是一个专门负责挑选显示File对象的内容的类。

下面就是源代码。看看,用了java.utils.Arrays.sort( )和11章的AlphabeticComparator之后,我们没费吹灰之力就对结果作了排序(按字母顺序): //:
c12:DirList.java
// Displays directory listing using regular expressions.
// {Args: "D.*\.java"}
import java.io.*;
import java.util.*;
import java.util.regex.*;
import com.bruceeckel.util.*;
public class DirList {
  public static void main(String[] args) {
    File path = new File(".");
    String[] list;
    if(args.length == 0)
      list = path.list();
    else
      list = path.list(new DirFilter(args[0]));
    Arrays.sort(list, new AlphabeticComparator());
    for(int i = 0; i < list.length; i++)
      System.out.println(list[i]);
  }
}
class DirFilter implements FilenameFilter {
  private Pattern pattern;
  public DirFilter(String regex) {
    pattern = Pattern.compile(regex);
  }
  public boolean accept(File dir, String name) {
    // Strip path information, search for regex:
    return pattern.matcher(
      new File(name).getName()).matches();
  }
} ///:~ 


DirFilter实现了FilenameFilter接口。我们来看看FilenameFilter究竟有多简单:
public interface FilenameFilter {
  boolean accept(File dir, String name);
}


也就是说,这类对象的任务就是提供一个accept( )的方法。之所以要创建这个类,就是要给list( )提供一个accept( )方法,这样当list( )判断该返回哪些文件名的时候,能够"回过头来调用"accept( )方法。因此,这种结构通常被称为回调(callback)。更准确地说,由于list( )实现了基本功能,而FilenameFilter提供了"对外服务所需的算法",因此这是一种"策略模式(Strategy Pattern)"。由于list( )拿FilenameFilter对象当参数,因此你可以将任何实现FilenameFilter接口的对象传给它,并以此(甚至是在运行时)控制list( )的工作方式。回调能提高程序的灵活性。

DirFilter还告诉我们,interface只是包含了一些方法,它没说你只能写这些方法。(但是,你至少要定义接口里有的方法。) 这里我们还定义了DirFilter的构造函数。

accept( )方法需要两个参数,一个是File对象,表示这个文件是在哪个目录里面的;另一个是String,表示文件名。虽然你可以忽略它们中的一个,甚至两个都不管,但是你大概总得用一下文件名吧。记住,list( )会对目录里的每个文件调用accept( ),并以此判断是不是把它包括到返回值里;这个判断依据就是accept( )的返回值。

切记,文件名里不能有路径信息。为此你只要用一个String对象来创建File对象,然后再调用这个File对象的getName( )就可以了。它会帮你剥离路径信息(以一种平台无关的方式)。然后再在accept( )里面用正则表达式(regular expression)的matcher对象判断,regex是否与文件名相匹配。兜完这个圈子,list( )方法返回了一个数组。

匿名内部类
这是用匿名内部类(详见第八章)来重写程序的绝佳机会。下面我们先创建一个返回FilenameFilter的filter( )方法。
//: c12:DirList2.java
// Uses anonymous inner classes.
// {Args: "D.*\.java"}
import java.io.*;
import java.util.*;
import java.util.regex.*;
import com.bruceeckel.util.*;
public class DirList2 {
  public static FilenameFilter filter(final String regex) {
    // Creation of anonymous inner class:
    return new FilenameFilter() {
      private Pattern pattern = Pattern.compile(regex);
      public boolean accept(File dir, String name) {
        return pattern.matcher(
          new File(name).getName()).matches();
      }
    }; // End of anonymous inner class
  }
  public static void main(String[] args) {
    File path = new File(".");
    String[] list;
    if(args.length == 0)
      list = path.list();
    else
      list = path.list(filter(args[0]));
    Arrays.sort(list, new AlphabeticComparator());
    for(int i = 0; i < list.length; i++)
      System.out.println(list[i]);
  }
} ///:~
 


注意,filter( )的参数必须是final的。要想在匿名内部类里使用其作用域之外的对象,只能这么做。

这是对前面所讲的代码的改进,现在FilenameFilter类已经与DirList2紧紧地绑在一起了。不过你还可以更进一步,把这个匿名内部类定义成list( )的参数,这样代码会变得更紧凑:
//: c12:DirList3.java
// Building the anonymous inner class "in-place."
// {Args: "D.*\.java"}
import java.io.*;
import java.util.*;
import java.util.regex.*;
import com.bruceeckel.util.*;
public class DirList3 {
  public static void main(final String[] args) {
    File path = new File(".");
    String[] list;
    if(args.length == 0)
      list = path.list();
    else
      list = path.list(new FilenameFilter() {  
        private Pattern pattern = Pattern.compile(args[0]);
        public boolean accept(File dir, String name) {
          return pattern.matcher(
            new File(name).getName()).matches();
        }
      });
    Arrays.sort(list, new AlphabeticComparator());
    for(int i = 0; i < list.length; i++)
      System.out.println(list[i]);
  }
} ///:~


现在该轮到main( )的参数成final了,因为匿名内部类要用它的arg[0]了。

这个例子告诉我们,可以用匿名内部类来创建专门供特定问题用的,一次性的类。这种做法的好处是,它能把解决某个问题的代码全都集中到一个地方。但是从另一角度来说,这样做会使代码的可读性变差,所以要慎重。




分享到:
评论

相关推荐

    匿名内部类实现接口回调

    简单接口回调demo。

    Android编程之匿名内部类与回调函数用法分析

    主要介绍了Android编程之匿名内部类与回调函数用法,结合实例形式分析了Android编程中所涉及的java匿名内部类与回调函数的概念、定义、使用方法与相关注意事项,需要的朋友可以参考下

    Android回调函数的例子

    Java回调函数的理解。通过在Android小程序下运行一个Java回调程序。代码内部有简单讲解。

    ssh框架整合分页--内部类回调函数

    上传的资料都是非常经典的,这也是我学习过程中的心得,希望大家能给我指点,也希望大家多上传资料共同学习。千万不要传空文件夹。。。 因为文件太大,所以分开上传,大家将其解压到同一个文件夹下即可

    c++ dll 消息回调

    dll调用c++程序函数,处理完成后,将消息返回给dll

    WCF回调与服务客户端示例

    1.采用代码方式进行服务客户端集成; 2.采用事件方式,将服务端内部消息传递至UI 3.采用回调方式,将服务端消息传递至Client 4.个人欠缺资源分,所以分数多要了点,抱歉

    关于javascript 回调函数中变量作用域的讨论

    1、背景 Javascript中的回调函数,相信大家都不陌生,最明显的例子是做Ajax请求时,提供的回调函数, 实际上DOM节点的事件处理方法(onclick,ondblclick等)也是回调函数。 在使用DWR的时候,回调函数可以作为第一个...

    详解Android中接口回调、方法回调

    在Android开发中我们很多地方都用到了方法的回调,回调就是把方法的定义和功能导入实现分开的一种机制,目的是为了解耦他的本质是基于观察者设计模式,即观察者设计模式的的简化版,例如:在下载时候的进度回调,在...

    Java内部类之间的闭包和回调详解

    相信闭包和回调对每位学习Java的人来说都不陌生,那么今天小编和大家分享一篇关于Java内部类之间的闭包和回调,有需要的可以参考借鉴。

    c语言从入门到实战-回调函数与qsort的讲解和模拟实现

    回调函数是一个函数,它作为参数传递给另一个函数,并且能够在该函数内部被调用。在C语言中,回调函数通常被用于实现事件处理和排序算法中。 `qsort`是C标准库中的一个排序函数,它可以对任意类型的数组进行排序。`...

    看了就懂的Promise和回调函数

    文章导航回调函数 (callback)什么是回调函数?为什么要使用回调PromisePromise是什么?...回调函数是在传给的函数内部被调用执行的。 示例 // 回调函数 function callback(param) { console.log('I am callback! p

    ES6之Promise解决回调地狱

    前端的ajax和jsonp内部充斥着大量的异步,为了能够拿到异步的数据,使用了大量的回调函数,来获取将来异步执行成功之后的数据。  从一定程度上来说,回调地狱能解决问题,但是有缺点,或者说不优雅,阅读性非常差...

    C#的回调机制浅析

    (和类在同一级,不是在某个方法内部的局部变量)。 3.设置: 代码如下:Form1.CheckForIllegalCrossThreadCalls = false;将检查合法跨线程调用设置为 false 表示不检查 项目开发中不允许这样使用,因此会导致非线程...

    使用回调接口实现ActiveX控件和它的容器程序的通讯

    所谓基于COM的回调虚接口实现ActiveX控件和客户端程序的通讯,大致是这样的,就是在ActiveX工程的内部的idl文件定义一个虚接口,在客户端程序定义一个虚接口的派生类来实现回调函数,在客户端程序传递派生类对象指针...

    python回调函数用法实例分析

    主要介绍了python回调函数用法,较为详细的分析了常用的调用方式,并实例介绍了Python回调函数的使用技巧,需要的朋友可以参考下

    swift-TableView分区索引回调

    UITableView内部的UITableViewIndex,实现滑动事件的监听回调

    当析构函数遇到多线程── C++ 中线程安全的对象回调

    编写线程安全的类不是难事,用同步原语保护内部状态即可。但是对象的生与死不能由对象自身拥有的互斥器来保护。如何保证即将析构对象 x 的时候,不会有另一个线程正在调用 x 的成员函数?或者说,如何保证在执行 x ...

    JavaScript闭包和回调详解

    2.函数内部可以引用外部的参数和变量; 3.参数和变量不会被垃圾回收机制回收。  闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个...

    微信公众号h5基础框架授权回调

    简介:已实现测试公众号授权回调功能 src/api:顾名思义,放接口请求的地方 public:关于微信或者全局共用的api接口 src/assets:静态资源 src/router:路由集合 store:vue的状态管理仓库 modules:此文件夹下...

Global site tag (gtag.js) - Google Analytics