龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > JAVA开发 >

Java运行时的子类识别

时间:2009-12-23 15:42来源:未知 作者:admin 点击:
分享到:
作者:仙人掌工作室 Java映像API(Reflection API)和Java 接口为编写可重用的代码提供了优秀的工具。以一个通用的命令启动器为例:假设你有一组执行各种任务的类,比如关闭或打开电灯

  作者:仙人掌工作室
  
  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;I<files.length;i++) {
  
  // 我们只对.class文件感爱好
  if (files[i].endsWith(".class")) {
  // 删除.class文件扩展名
  String classname = files[i].substring(0,files[i].length()-6);
  try {
  // 尝试创建该对象的一个实例
  Object o = Class.forName(pckgname+"."+classname).newInstance();
  if (o instanceof Command) {
  System.out.println(classname);
  }
  } catch (ClassNotFoundException cnfex) {
  System.err.println(cnfex);
  } catch (InstantiationException iex) {
  // 我们试图实例化一个接口或者
  // 一个没有默认构造函数的对象
  } catch (IllegalAccessException iaex) {
  // 该类不是公用类
  }
  }
  }
  }
  }
  
  
  
  要执行手头的任务,我们只需稍微修改一下原来的启动器。
  
精彩图集

赞助商链接