第11章先容了Java 1.1新的“反射”观念,并操作这个观念查询一个特定类的要领——要么是由所有要领组成的一个完整列表,要么是这个列表的一个子集(名字与我们指定的要害字相符)。谁人例子最大的长处就是能自动显示出所有要领,不强迫我们在担任布局中遍历,查抄每一级的基本类。所以,它实际是我们节减编程时间的一个有效东西:因为大大都Java要领的名字都划定得很是全面和详尽,所以能有效地找出那些包括了一个非凡要害字的要领名。若找到切合尺度的一个名字,便可按照它直接查阅联机辅佐文档。
但第11的谁人例子也有缺陷,它没有利用AWT,仅是一个纯呼吁行的应用。在这儿,我们筹备建造一个改造的GUI版本,能在我们键入字符的时候自动刷新输出,也答允我们在输出功效中举办剪切和粘贴操纵:
//: DisplayMethods.java // Display the methods of any class inside // a window. Dynamically narrows your search. import java.awt.*; import java.awt.event.*; import java.applet.*; import java.lang.reflect.*; import java.io.*; public class DisplayMethods extends Applet { Class cl; Method[] m; Constructor[] ctor; String[] n = new String[0]; TextField name = new TextField(40), searchFor = new TextField(30); Checkbox strip = new Checkbox("Strip Qualifiers"); TextArea results = new TextArea(40, 65); public void init() { strip.setState(true); name.addTextListener(new NameL()); searchFor.addTextListener(new SearchForL()); strip.addItemListener(new StripL()); Panel top = new Panel(), lower = new Panel(), p = new Panel(); top.add(new Label("Qualified class name:")); top.add(name); lower.add( new Label("String to search for:")); lower.add(searchFor); lower.add(strip); p.setLayout(new BorderLayout()); p.add(top, BorderLayout.NORTH); p.add(lower, BorderLayout.SOUTH); setLayout(new BorderLayout()); add(p, BorderLayout.NORTH); add(results, BorderLayout.CENTER); } class NameL implements TextListener { public void textValueChanged(TextEvent e) { String nm = name.getText().trim(); if(nm.length() == 0) { results.setText("No match"); n = new String[0]; return; } try { cl = Class.forName(nm); } catch (ClassNotFoundException ex) { results.setText("No match"); return; } m = cl.getMethods(); ctor = cl.getConstructors(); // Convert to an array of Strings: n = new String[m.length + ctor.length]; for(int i = 0; i < m.length; i++) n[i] = m[i].toString(); for(int i = 0; i < ctor.length; i++) n[i + m.length] = ctor[i].toString(); reDisplay(); } } void reDisplay() { // Create the result set: String[] rs = new String[n.length]; String find = searchFor.getText(); int j = 0; // Select from the list if find exists: for (int i = 0; i < n.length; i++) { if(find == null) rs[j++] = n[i]; else if(n[i].indexOf(find) != -1) rs[j++] = n[i]; } results.setText(""); if(strip.getState() == true) for (int i = 0; i < j; i++) results.append( StripQualifiers.strip(rs[i]) + "\n"); else // Leave qualifiers on for (int i = 0; i < j; i++) results.append(rs[i] + "\n"); } class StripL implements ItemListener { public void itemStateChanged(ItemEvent e) { reDisplay(); } } class SearchForL implements TextListener { public void textValueChanged(TextEvent e) { reDisplay(); } } public static void main(String[] args) { DisplayMethods applet = new DisplayMethods(); Frame aFrame = new Frame("Display Methods"); aFrame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); aFrame.add(applet, BorderLayout.CENTER); aFrame.setSize(500,750); applet.init(); applet.start(); aFrame.setVisible(true); } } class StripQualifiers { private StreamTokenizer st; public StripQualifiers(String qualified) { st = new StreamTokenizer( new StringReader(qualified)); st.ordinaryChar(' '); } 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; } } ///:~
#p#分页标题#e#
措施中的有些对象已在以前见地过了。和本书的很多GUI措施一样,这既可作为一个独立的应用措施利用,亦可作为一个措施片(Applet)利用。另外,StripQualifiers类与它在第11章的表示是完全一样的。
GUI包括了一个名为name的“文本字段”(TextField),或在个中输入想查找的类名;还包括了另一个文本字段,名为searchFor,可选择性地在个中输入必然的文字,但愿在要领列表中查找那些文字。Checkbox(复选框)答允我们指出最终但愿在输出中利用完整的名字,照旧将前面的各类限定信息删去。最后,功效显示于一个“文本区域”(TextArea)中。
各人会留意到这个措施未利用任何按钮或其他组件,不能用它们开始一次搜索。这是由于无论文本字段照旧复选框城市受到它们的“侦听者(Listener)工具的监督。只要作出一项改变,功效列表便会当即更新。若改变了name字段中的文字,新的文字就会在NameL类中捕捉。若文字不为空,则在Class.forName()顶用于实验查找类。虽然,在文字键入期间,名字大概会变得不完整,而Class.forName()会失败,这意味着它会“掷”出一个违例。该违例会被捕捉,TextArea会随之设为“Nomatch”(没有相符)。但只要键入了一个正确的名字(巨细写也算在内),Class.forName()就会乐成,而getMethods()和getConstructors()会别离返回由Method和Constructor工具组成的一个数组。这些数组中的每个工具城市通过toString()转酿成一个字串(这样便发生了完整的要领或构建器签名),并且两个列表城市归并到n中——一个独立的字串数组。数组n属于DisplayMethods类的一名成员,并在挪用reDisplay()时用于显示的更新。
若改变了Checkbox或searchFor组件,它们的“侦听者”会简朴地挪用reDisplay()。reDisplay()会建设一个姑且数组,个中包括了名为rs的字串(rs代表“功效集”——Result Set)。功效集要么直接从n复制(没有find要害字),要么选择性地从包括了find要害字的n中的字串复制。最后会查抄strip Checkbox,看看用户是不是但愿将名字中多余的部门删除(默认为“是”)。若谜底是必定的,则用StripQualifiers.strip()做这件工作;反之,就将列表简朴地显示出来。
在init()中,各人也许认为在配置机关时需要举办大量沉重的事情。事实上,组件的部署完全大概只需要少少的事情。但象这样利用BorderLayout的长处是它答允用户改变窗口的巨细,并出格能使TextArea(文本区域)更大一些,这意味着我们可以改变巨细,以便毋需转动即可看到更长的名字。
编程时,各人会发明出格有须要让这个东西处于运行状态,因为在试图判定要挪用什么要领的时候,它提供了最好的要领之一。