快捷搜索:  as  2018  FtCWSyGV  С˵  test  xxx  Ψһ  w3viyKQx

澳门新葡萄app下载_龟发之家论坛



作者:神仙掌事情室本文选自:赛迪网2002年02月08日

Java映像API(Reflection API)和Java 接口为编写可重用的代码供给了优秀的对象。以一个通用的敕令启动器为例:假设你有一组履行各类义务的类,比如关闭或打开电灯,打开、关闭或锁上门,等等。这些类的名字分手是LightOn、LightOff、DoorOpen、DoorClose和DoorLock,所有这些类都实现了Command接口。

Command接口的定义如下:

public interface Command {

public void process();

}

你可以编写一个简单的通用启动器,如下所示:

public class Launcher{

public static void main(String[] args){

if (args.length>0) {

try {

Command command =

(Command)Class.forName(args[0]).newInstance();

command.process();

} catch (Exception ex) {

System.out.println("Invalid command");

}

} else {

System.out.println("Usage: Launcher ");

}

}

// Launcher

这个法度榜样用Class.forName措施得到参数中指定类的Class工具,然后用newInstance()措施创建该类的一个实例。根据要求,该类实现了Command接口,以是法度榜样把工具定型(cast)成为Command,然后调用process()措施,由process措施履行实际义务。假如呈现了非常,比如因为类的名字拼写差错或安然方面的问题,法度榜样将显示一个“Invalid command”信息。

这个敕令启动器可以按照如下要领应用:

%java Launcher LightOn

今后假如实现了一些新的义务,敕令启动器也不必要改动。从法度榜样员的角度来看,这确凿很不错。然则,它对付用户来说又若何呢?假设一个用户输入了以下敕令:

%java Launcher OpenDoor

Invalid command

“Invalid command”的意思是用户不能打开门吗?不是,它只表示类命名差错(DoorOpen变成了OpenDoor)。以是,法度榜样应该容许用户查看可用敕令的清单。要包管敕令启动器的通用性,用户应该能够在运行时查找这些敕令。

Java映像API能够在运行时供给大年夜量有关指定类的信息:我们可以方便地获知指定类的所有超类、它所实现的接口、措施、构造函数、域,等等。但在这里,我们感兴趣的是所有实现特定接口的类,这种信息无法从Java映像API直接得到。本文余下的部分就为你先容若何获取实现了特定接口的类的信息。

改进通用敕令启动器的用户界面 在Java中,包对应着目录,经由过程File工具的list()措施获取包孕在包中的所有类是很轻易的。我们的做法是使用instanceof语句进行反省:对付包里面的每一个类文件,响应的类是否实现了Command接口。这意味着只反省每一个类文件的公用类,而且接口和它的实现必须在一个包里面。下面是代码: public static void find(String pckgname) {

// 把包名字转换成绝对路径

String name = new String(pckgname);

if (!name.startsWith("/")) {

name = "/" + name;

}

name = name.replace(´.´,´/´);

// 得到一个File工具

URL url = Launcher.class.getResource(name);

File directory = new File(url.getFile());

if (directory.exists()) {

// 得到包里面的文件清单

String [] files = directory.list();

for (int i=0;I0) {

try {

Command command = (Command)Class.forName("commands."+

args[0]).newInstance();

command.process();

} catch (Exception ex) {

System.out.println("Invalid command");

System.out.println("Available commands:");

find("commands");

}

} else {

System.out.println("Usage: Launcher ");

}

}

下面是履行差错的敕令时,改进后的启动器显示的结果:

%java Launcher OpenDoor

Invalid command

Available commands:

LightOn

LightOff

DoorOpen

DoorClose

DoorLock

运行时子类识别 我们澳门新葡萄app下载可以改动find()措施,让它能够探求指定类的任何子类。为此,我们要用到instanceof的动态版本,即isInstance()。用(tosubclass.isInstance(o))调换(o instanceof Command),此中tosubclass是find()措施参数中指定的类。现在我们有了一个措施,它能够在指定的包中找出指定类的任何子类。我们可以改进这个措施,让它在当前已装入的包中探求子类。为此,我们要用到Package.getPackages()措施,这个措施正确地返回当前类装载器装入的各个包。然后,我们只需针对每一个包调用find()措施: public static void find(String tosubclassname) {

try {

Class tosubclass = Class.forName(tosubclassname);

Package [] pc澳门新葡萄app下载ks = Package.getPackages();

for (int i=0;I

find(pcks[i].getName(),tosubclass);

}

} catch (ClassNotFoundException ex) {

System.err.println("Class "+tosubclassname+" not found!");

}

}

这个措施的返回结果主要依附于它被调用的光阴。对付本文的通用敕令启动器,调用find()措施时装入内存的只有少量几个包。例如,下面是在我的NT机械上调用find()之前装入的包:

package java.util.zip,Java Platform API Specification,version 1.3

package java.security,Java Platform API Specification,version 1.3

package java.io,Java Platform API Specification,version 1.3

package sun.net.www.protocol.file,Java Platform API Specification,version 1.3

package sun.net.www.protocol.jar,Java Platform API Specification,version 1.3

package sun.net.www,Java Platform API Specification,version 1.3

package java.util.jar,Java Platform API Specification,version 1.3

package sun.security.action,Java Platform API Specification,version 1.3

package java.lang,Java Platform API Specification,version 1.3

package澳门新葡萄app下载 sun.io,Java Platform API Specification,version 1.3

package java.util,Java Platform API Specification,version 1.3

package sun.misc,Java Platform API Specification,version 1.3

package java.security.cert,Java Platform API Specification,version 1.3

package java.lang.reflect,Java Platform API Specification,version 1.3

package澳门新葡萄app下载 java.net,Java Platform API Specification,version 1.3

package sun.security.util,Java Platform API Specification,version 1.3

package java.lang.ref,Java Platform API Specification,version 1.3

package sun.security.provider,Java Platform API Specification,version 1.3

package com.sun.rsajca

由于在敕令启动器中,接口和它的所有实现都在同一个包里面,装入类之后就可以获得已经装入的包。是以,我们可以在该包里面搜索子类。这是探求相关包的独一措施。RTSI类的完备源代码可以在本文着末的参考资本找到。解开下载包的ZIP压缩之后,你可以用下面的敕令测试代码:

% java -cp classes RTSI commands.Command

关于jar文件 当包以操作系统目录和文件的形式存在时,前面评论争论的代码能够顺利地运行;但假如类文件在一个或者澳门新葡萄app下载多个jar文件里面,这些代码不再有效。在本文的下载代码中,你将发明该问题的一个办理规划。你可以用下面的敕令测试法度榜样处置惩罚jar文件的能力: % java -jar RTSI.jar commands.Command

■ 停止语

在这篇文章中,我们评论争论了若何在一个指定的包里面(或从已经装入的包)动态地提取所有指定类的子类。这个功能不仅对付设计通用法度榜样很有用,而且正如本文的敕令启动器实例所显示的,它对用户同样有好处。

作者申明:一些读者指出,本文的法度榜样只能检测拥有默认构造函数的子类。他们建议用Class的isAssignableFrom()措施替代isInstance()。

您可能还会对下面的文章感兴趣: