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

回调和内部类

    博客分类:
  • 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]了。

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




分享到:
评论

相关推荐

    匿名内部类实现接口回调

    在Java编程中,接口回调是一种常见的设计模式,用于在对象之间传递异步事件或实现通信。这个"匿名内部类实现接口...在分析和实现"匿名内部类实现接口回调"的示例时,我们可以深入理解这些原理并将其应用于实际项目中。

    易语言类方法回调

    总的来说,易语言类方法回调涉及了面向对象编程的关键概念,包括类、方法、句柄和动态调用。掌握这些知识将有助于你编写出更加灵活、可扩展的易语言程序。通过实践和理解提供的源码,你将能够更好地应对各种编程挑战...

    易语言类回调新

    通过对“易语言类回调新源码”的仔细分析,开发者能够掌握类回调新机制的具体实现,如何将回调函数与类和方法相结合,以及消息处理在其中扮演的角色。这对于提升编程技能、进行有效的问题诊断和程序优化都是大有裨益...

    C++将类的成员函数作为回调函数

    ### C++将类的成员函数作为回调函数 #### 背景与问题 在C++编程中,回调函数是一种常见的设计模式,它允许程序在特定的事件或条件下调用一个预先注册的函数。然而,当涉及到类的成员函数时,事情变得稍微复杂了...

    java 回调函数 实现

    7. **匿名内部类**:在Java中,为了简洁,有时可以使用匿名内部类来实现回调接口。这样可以避免为短暂使用的监听器类创建单独的文件。例如,在`CallMeTest.java`中,可能有类似这样的代码: ```java button....

    回调 3 回调 3

    回调函数允许应用程序提供一段代码,这段代码会在非托管DLL函数内部被调用,从而允许自定义处理或控制流程。回调函数在托管代码(如C#)与非托管代码之间架起了一座桥梁,使得它们能够协同工作。 标题和描述中提到...

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

    SSH框架整合分页——内部类回调函数 SSH(Spring、Struts2、Hibernate)是Java Web开发中常用的一种集成框架,它将Spring的IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面...

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

    在Android编程中,匿名内部类和回调函数是两个非常重要的概念,它们在事件处理、接口交互等场景中扮演着核心角色。这篇文章将深入探讨这两个概念,以及如何在实际开发中运用它们。 首先,让我们理解匿名内部类。...

    内部类 匿名内部类 内部接口 对比说明

    内部类是Java编程语言中的一种特性,它允许我们在一个类...在Android开发中,它们常用于事件监听、线程管理、回调函数等场景,增强了代码的灵活性和可读性。理解这些概念并熟练运用,对于提升软件设计的质量至关重要。

    android中的回调机制

    Java 中的回调是通过接口或内部类实现的。 回调机制的实现需要两个类和一个接口,步骤如下: 1. 首先定义一个接口,也就是回调接口 CallBack,内部包含回调方法; 2. 定义一个类 A,可称为客户端,在该类中提供...

    java 内部类使用(内部匿名类)

    它们常用于实现接口或继承一个类,特别是在事件处理、回调机制和简短的辅助类中。创建匿名内部类的方式是在实例化类时直接定义类的实现,不需要声明类名。 3. **方法参数内部类**:这是一种特殊类型的局部内部类,...

    delphi封装的回调函数DLL

    3. **封装回调函数**:在DLL中封装回调函数意味着将回调函数的定义和实现放在DLL内部,只暴露一个接口供外部调用。这样可以隐藏实现细节,提高代码的重用性和安全性。 4. **调用约定**:在Delphi中,不同的调用约定...

    Java中的回调使用

    在Java中,回调并不是语言内置的特性,但可以通过接口、匿名内部类或Java 8引入的Lambda表达式来实现。 首先,我们来看如何使用接口实现回调。假设有一个`Calculator`接口,它定义了一个`calculateDone`方法: ```...

    回调和代理

    在IT行业中,回调和代理是两种常见的对象间通信机制,特别是在Objective-C和Swift等Apple的开发框架中。本文将深入探讨这两个概念,并结合"block"这一特定标签进行讲解。 首先,我们来理解什么是回调。回调是一种...

    易语言类中窗口回调的正确使用方法

    易语言类中的窗口回调,允许程序员自定义窗口的行为,以满足特定的应用需求。在本教程中,我们将深入探讨易语言类中窗口回调的正确使用方法。 首先,我们需要了解窗口回调的基本概念。在易语言中,每个窗口都有一个...

    delphi Dll的回调函数

    在Delphi的DLL上下文中,回调函数通常用于处理异步操作或者在DLL内部完成某些计算后通知调用者结果。这为开发者提供了灵活的方式来实现通信和事件处理。 创建一个Delphi DLL的回调函数,首先需要定义一个回调原型,...

    delphi 回调函数示例

    `CallBackDemo` 可能是一个完整的 Delphi 示例项目,展示了如何在 Delphi 应用程序内部使用回调函数。这通常涉及到定义一个函数类型,然后在需要的地方传入该函数的引用。例如: ```delphi type TCallbackProc = ...

    java自定义回调函数

    在Java中,我们可以使用接口或者匿名内部类来实现回调机制。 首先,我们需要理解什么是回调。回调是一种编程技术,当一个函数执行完毕后,它会调用另一个预先指定的函数,这个被调用的函数就是回调函数。在Java中,...

    C++ 回调函数

    回调函数在C++编程中是一种重要的设计模式,它允许我们传递一个函数作为参数到另一个函数,然后在适当的时候由那个函数内部调用。这种机制在处理异步操作、事件驱动编程、用户自定义行为等方面非常常见。下面我们将...

Global site tag (gtag.js) - Google Analytics