java中的基础类方法提取器

    作者:课课家教育更新于: 2016-02-21 16:17:58

    大神带你学编程,欢迎选课

      很少需要直接使用反射工具;之所以在语言中提供它们,仅仅是为了支持其他java特性,比如对象序列化、Java Beans以及RMI(本章后面介绍)。但是,我们许多时候仍然需要动态提取与一个类有关的资料。其中特别有用的工具便是一个类方法提取器。正如前面指出的那样,若检视类定义源码或者联机文档,只能看到在那个类定义中被定义或覆盖的方法,基础类那里还有大量资料拿不到。幸运的是,“反射”做到了这一点,可用它写一个简单的工具,令其自动展示整个接口。下面便是具体的程序:

    java中的基础类方法提取器_Java基础类_Java构建器_课课家

      //: ShowMethods.java

      // Using Java 1.1 reflection to show all the

      // methods of a class, even if the methods are

      // defined in the base class.

      import java.lang.reflect.*;

      public class ShowMethods {

      static final String usage =

      "usage: \\n" +

      "ShowMethods qualified.class.name\\n" +

      "To show all methods in class or: \\n" +

      "ShowMethods qualified.class.name word\\n" +

      "To search for methods involving 'word'";

      public static void main(String[] args) {

      if(args.length < 1) {

      System.out.println(usage);

      System.exit(0);

      }

      try {

      Class c = Class.forName(args[0]);

      Method[] m = c.getMethods();

      Constructor[] ctor = c.getConstructors();

      if(args.length == 1) {

      for (int i = 0; i < m.length; i++)

      System.out.println(m[i].toString());

      for (int i = 0; i < ctor.length; i++)

      System.out.println(ctor[i].toString());

      }

      else {

      for (int i = 0; i < m.length; i++)

      if(m[i].toString()

      .indexOf(args[1])!= -1)

      System.out.println(m[i].toString());

      for (int i = 0; i < ctor.length; i++)

      if(ctor[i].toString()

      .indexOf(args[1])!= -1)

      System.out.println(ctor[i].toString());

      }

      } catch (ClassNotFoundException e) {

      System.out.println("No such class: " + e);

      }

      }

      } ///:~

      Class方法getMethods()和getConstructors()可以分别返回Method和Constructor的一个数组。每个类都提供了进一步的方法,可解析出它们所代表的方法的名字、参数以及返回值。但也可以象这样一样只使用toString(),生成一个含有完整方法签名的字串。代码剩余的部分只是用于提取命令行信息,判断特定的签名是否与我们的目标字串相符(使用indexOf()),并打印出结果。

      这里便用到了“反射”技术,因为由Class.forName()产生的结果不能在编译期间获知,所以所有方法签名信息都会在运行期间提取。若研究一下联机文档中关于“反射”(Reflection)的那部分文字,就会发现它已提供了足够多的支持,可对一个编译期完全未知的对象进行实际的设置以及发出方法调用。同样地,这也属于几乎完全不用我们操心的一个步骤——Java自己会利用这种支持,所以程序设计环境能够控制Java Beans——但它无论如何都是非常有趣的。

      一个有趣的试验是运行java ShowMehods ShowMethods。这样做可得到一个列表,其中包括一个public默认构建器,尽管我们在代码中看见并没有定义一个构建器。我们看到的是由编译器自动合成的那一个构建器。如果随之将ShowMethods设为一个非public类(即换成“友好”类),合成的默认构建器便不会在输出结果中出现。合成的默认构建器会自动获得与类一样的访问权限。

      ShowMethods的输出仍然有些“不爽”。例如,下面是通过调用java ShowMethods java.lang.String得到的输出结果的一部分:

      public boolean

      java.lang.String.startsWith(java.lang.String,int)

      public boolean

      java.lang.String.startsWith(java.lang.String)

      public boolean

      java.lang.String.endsWith(java.lang.String)

      若能去掉象java.lang这样的限定词,结果显然会更令人满意。有鉴于此,解决这个问题:

      //: ShowMethodsClean.java

      // ShowMethods with the qualifiers stripped

      // to make the results easier to read

      import java.lang.reflect.*;

      import java.io.*;

      public class ShowMethodsClean {

      static final String usage =

      "usage: \\n" +

      "ShowMethodsClean qualified.class.name\\n" +

      "To show all methods in class or: \\n" +

      "ShowMethodsClean qualif.class.name word\\n" +

      "To search for methods involving 'word'";

      public static void main(String[] args) {

      if(args.length < 1) {

      System.out.println(usage);

      System.exit(0);

      }

      try {

      Class c = Class.forName(args[0]);

      Method[] m = c.getMethods();

      Constructor[] ctor = c.getConstructors();

      // Convert to an array of cleaned Strings:

      String[] n =

      new String[m.length + ctor.length];

      for(int i = 0; i < m.length; i++) {

      String s = m[i].toString();

      n[i] = StripQualifiers.strip(s);

      }

      for(int i = 0; i < ctor.length; i++) {

      String s = ctor[i].toString();

      n[i + m.length] =

      StripQualifiers.strip(s);

      }

      if(args.length == 1)

      for (int i = 0; i < n.length; i++)

      System.out.println(n[i]);

      else

      for (int i = 0; i < n.length; i++)

      if(n[i].indexOf(args[1])!= -1)

      System.out.println(n[i]);

      } catch (ClassNotFoundException e) {

      System.out.println("No such class: " + e);

      }

      }

      }

      class StripQualifiers {

      private StreamTokenizer st;

      public StripQualifiers(String qualified) {

      st = new StreamTokenizer(

      new StringReader(qualified));

      st.ordinaryChar(' '); // Keep the spaces

      }

      public String getNext() {

      String s = null;

      try {

      if(st.nextToken() !=

      StreamTokenizer.TT_EOF) {

      switch(st.ttype) {

      case StreamTokenizer.TT_EOL:

      s = null;

      break;

      case StreamTokenizer.TT_NUMBER:

      s = Double.toString(st.nval);

      break;

      case StreamTokenizer.TT_WORD:

      s = new String(st.sval);

      break;

      default: // single character in ttype

      s = String.valueOf((char)st.ttype);

      }

      }

      } catch(IOException e) {

      System.out.println(e);

      }

      return s;

      }

      public static String strip(String qualified) {

      StripQualifiers sq =

      new StripQualifiers(qualified);

      String s = "", si;

      while((si = sq.getNext()) != null) {

      int lastDot = si.lastIndexOf('.');

      if(lastDot != -1)

      si = si.substring(lastDot + 1);

      s += si;

      }

      return s;

      }

      } ///:~

      ShowMethodsClean方法非常接近前一个ShowMethods,只是它取得了Method和Constructor数组,并将它们转换成单个String数组。随后,每个这样的String对象都在StripQualifiers.Strip()里“过”一遍,删除所有方法限定词。正如大家看到的那样,此时用到了StreamTokenizer和String来完成这个工作。

      假如记不得一个类是否有一个特定的方法,而且不想在联机文档里逐步检查类结构,或者不知道那个类是否能对某个对象(如Color对象)做某件事情,该工具便可节省大量编程时间。

课课家教育

未登录