按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
11。3。1 一个类方法提取器
很少需要直接使用反射工具;之所以在语言中提供它们,仅仅是为了支持其他Java 特性,比如对象序列化
(第10章介绍)、Java Beans 以及RMI (本章后面介绍)。但是,我们许多时候仍然需要动态提取与一个类
有关的资料。其中特别有用的工具便是一个类方法提取器。正如前面指出的那样,若检视类定义源码或者联
机文档,只能看到在那个类定义中被定义或覆盖的方法,基础类那里还有大量资料拿不到。幸运的是,“反
射”做到了这一点,可用它写一个简单的工具,令其自动展示整个接口。下面便是具体的程序:
//: 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。namen〃 +
〃To show all methods in class or: n〃 +
〃ShowMethods qualified。class。name wordn〃 +
〃To search for methods involving 'word'〃;
public static void main(String'' args) {
if(args。length 《 1) {
System。out。println(usage);
System。exit(0);
}
try {
344
…………………………………………………………Page 346……………………………………………………………
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 这样的限定词,结果显然会更令人满意。有鉴于此,可引入上一章介绍的
StreamTokenizer 类,解决这个问题:
//: ShowMethodsClean。java
345
…………………………………………………………Page 347……………………………………………………………
// 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。namen〃 +
〃To show all methods in class or: n〃 +
〃ShowMethodsClean qualif。class。name wordn〃 +
〃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
346
…………………………………………………………Page 348……………………………………………………………
}
public String getNext() {
String s = null;
try {
if(s