以下是我在学习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编程中,接口回调是一种常见的设计模式,用于在对象之间传递异步事件或实现通信。这个"匿名内部类实现接口...在分析和实现"匿名内部类实现接口回调"的示例时,我们可以深入理解这些原理并将其应用于实际项目中。
总的来说,易语言类方法回调涉及了面向对象编程的关键概念,包括类、方法、句柄和动态调用。掌握这些知识将有助于你编写出更加灵活、可扩展的易语言程序。通过实践和理解提供的源码,你将能够更好地应对各种编程挑战...
3. **子程序与方法**:理解易语言中的函数和类方法的定义、调用以及它们在程序流程中的作用。 4. **消息处理**:"msg"可能指的是消息处理,这在GUI编程中很常见,如窗口消息、事件消息等。 5. **源码分析**:如何...
### C++将类的成员函数作为回调函数 #### 背景与问题 在C++编程中,回调函数是一种常见的设计模式,它允许程序在特定的事件或条件下调用一个预先注册的函数。然而,当涉及到类的成员函数时,事情变得稍微复杂了...
7. **匿名内部类**:在Java中,为了简洁,有时可以使用匿名内部类来实现回调接口。这样可以避免为短暂使用的监听器类创建单独的文件。例如,在`CallMeTest.java`中,可能有类似这样的代码: ```java button....
SSH框架整合分页——内部类回调函数 SSH(Spring、Struts2、Hibernate)是Java Web开发中常用的一种集成框架,它将Spring的IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面...
回调函数允许应用程序提供一段代码,这段代码会在非托管DLL函数内部被调用,从而允许自定义处理或控制流程。回调函数在托管代码(如C#)与非托管代码之间架起了一座桥梁,使得它们能够协同工作。 标题和描述中提到...
在Android编程中,匿名内部类和回调函数是两个非常重要的概念,它们在事件处理、接口交互等场景中扮演着核心角色。这篇文章将深入探讨这两个概念,以及如何在实际开发中运用它们。 首先,让我们理解匿名内部类。...
内部类是Java编程语言中的一种特性,它允许我们在一个类...在Android开发中,它们常用于事件监听、线程管理、回调函数等场景,增强了代码的灵活性和可读性。理解这些概念并熟练运用,对于提升软件设计的质量至关重要。
Java 中的回调是通过接口或内部类实现的。 回调机制的实现需要两个类和一个接口,步骤如下: 1. 首先定义一个接口,也就是回调接口 CallBack,内部包含回调方法; 2. 定义一个类 A,可称为客户端,在该类中提供...
它们常用于实现接口或继承一个类,特别是在事件处理、回调机制和简短的辅助类中。创建匿名内部类的方式是在实例化类时直接定义类的实现,不需要声明类名。 3. **方法参数内部类**:这是一种特殊类型的局部内部类,...
3. **封装回调函数**:在DLL中封装回调函数意味着将回调函数的定义和实现放在DLL内部,只暴露一个接口供外部调用。这样可以隐藏实现细节,提高代码的重用性和安全性。 4. **调用约定**:在Delphi中,不同的调用约定...
在Java中,回调并不是语言内置的特性,但可以通过接口、匿名内部类或Java 8引入的Lambda表达式来实现。 首先,我们来看如何使用接口实现回调。假设有一个`Calculator`接口,它定义了一个`calculateDone`方法: ```...
在IT行业中,回调和代理是两种常见的对象间通信机制,特别是在Objective-C和Swift等Apple的开发框架中。本文将深入探讨这两个概念,并结合"block"这一特定标签进行讲解。 首先,我们来理解什么是回调。回调是一种...
易语言类中的窗口回调,允许程序员自定义窗口的行为,以满足特定的应用需求。在本教程中,我们将深入探讨易语言类中窗口回调的正确使用方法。 首先,我们需要了解窗口回调的基本概念。在易语言中,每个窗口都有一个...
在Delphi的DLL上下文中,回调函数通常用于处理异步操作或者在DLL内部完成某些计算后通知调用者结果。这为开发者提供了灵活的方式来实现通信和事件处理。 创建一个Delphi DLL的回调函数,首先需要定义一个回调原型,...
`CallBackDemo` 可能是一个完整的 Delphi 示例项目,展示了如何在 Delphi 应用程序内部使用回调函数。这通常涉及到定义一个函数类型,然后在需要的地方传入该函数的引用。例如: ```delphi type TCallbackProc = ...
在Java中,我们可以使用接口或者匿名内部类来实现回调机制。 首先,我们需要理解什么是回调。回调是一种编程技术,当一个函数执行完毕后,它会调用另一个预先指定的函数,这个被调用的函数就是回调函数。在Java中,...
回调函数在C++编程中是一种重要的设计模式,它允许我们传递一个函数作为参数到另一个函数,然后在适当的时候由那个函数内部调用。这种机制在处理异步操作、事件驱动编程、用户自定义行为等方面非常常见。下面我们将...