Java泛型代码 - 反射,轻松搞定






3.86/5 (7投票s)
使用这个工具类,让Java的反射变得更容易。
引言
在你担任软件设计师/程序员的职业生涯中,你可能会遇到在运行时使用对象的需求,而对它们在设计时了解不多。Java通过反射来实现这一点。
Java泛型代码 - 轻松处理反射
如果你曾使用过JDBC,那么下面的代码会让你觉得熟悉
public Connection getConnection(String driverClass, String dbUrl, String userName,
String passWord) {
Connection connection = null;
try {
if (Class.forName(driverClass) != null) {
connection = DriverManager.getConnection(dbURL, userName, passWord);
if (connection != null) {
connection.setAutoCommit(false);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return connection;
}
如果你写过类似的代码,你就用过反射。
它究竟是什么?
反射是一组API,Java使用它们来解决各种问题。例如,使用IDE设计GUI涉及操作大量控件,将它们添加到框架中并调整它们的属性。你的IDE(如果用Java编写)会使用反射来加载类,确定它们有哪些属性,让你修改这些属性,并调用对象中的适当方法来将属性更改为你选择的值。
我们能用它做什么?
如你所知,运行时对象必须被加载,并且拥有字段和方法。因此,反射主要关注三件事:
- 当你只知道类名而在运行时加载类。
- 在不知道对象字段名称或类型的情况下访问它们的字段。
- 调用这些匿名对象的方
为什么它很困难?
熟悉Java的反射API可能是一项挑战,尤其是在时间紧迫的情况下。因此,我将我关于反射的大部分知识收集到一个易于使用的工具类中。我将通过一个演示程序简要介绍这个类。
演示
演示程序非常简单:我将尝试按其完全限定名(即包名+类名)加载一个类,然后通过调用一个我仅知道名称的方法来操作它。
演示代码的类结构如下:
- dev.easyref.tester:
DemoApplication
- 演示的主类。 - dev.easyref.data :
Employee
- 一个简单的我将在运行时加载的数据类。 - dev.easyref.util:
Arguments
- 用于执行所有反射工作的工具类。
下面的Employee类仅包含信息
public class Employee {
// These are the data-members, notice that we can never access them externally..
private int age;
private float salary;
private String firstName;
private String lastName;
public Employee(String firstName, String lastName, int age, float salary) {
this.age = age;
this.salary = salary;
this.firstName = firstName;
this.lastName = lastName;
}
public void updateSalary(float increase) {
salary += increase;
}
public String toString() {
return "<Employee Name: [" + firstName + ", " + lastName + "], Age: [" + age + "], "
"Salary: [" + salary + "]>";
}
}
演示代码按如下方式操作Employee类
1: import dev.easyref.util.*;
2: public class DemoApplication {
3: public static void main(String[] args) {
4: // Create an Arguments object..
5: Arguments xArgs = new Arguments();
6: // Fill the Arguments object with data..
7: xArgs.addElement("Doron");
8: xArgs.addElement("Barak");
9: xArgs.addElement(36);
10: xArgs.addElement(3000.0f);
11: // Create an instance of an Employee class based on the data..
12: Object o = xArgs.getInstance("dev.easyref.data.Employee");
13: // Show the object that we received..
14: System.out.println("Created instance >> " + o);
15: // Create a new Arguments object, collecting the data in the object..
16: xArgs = new Arguments(o);
17: // Display the collected data..
18: System.out.println("Instace data >> " + xArgs);
19: // Change the first stored value to 1000..
20: xArgs.setElementAt(1000.0f, 1);
21: // Order the Arguments object to not print Excpetion stacks..
22: xArgs.hideExceptions();
23: // Invoke the updateSalary() method of the Employee instance..
24: xArgs.runMethod(o, "updateSalary");
25: // Check to see if we had an Excpetion..
26: if (xArgs.hadMethodError()) {
27: // Remove unwanted values from the Arguments object..
28: xArgs.removeElementAt(0);
29: xArgs.removeElementAt(1);
30: xArgs.removeElementAt(1);
31: // Now, we try to invoke updateSalary() again..
32: xArgs.runMethod(o, "updateSalary");
33: }
34: // Display object after Salary raise..
35: System.out.println("After Salary Raise >> " + o);
36: }
37: }
第5-10行
从第5-10行开始,创建一个Arguments
对象,并向其中添加数据。数据的添加顺序与使用Employee
类的构造函数时出现的顺序相同。我的Arguments
对象继承自Java的Vector
对象,以便于操作其数据元素。
第12-14行
在这里,Arguments
对象用于获取dev.easyref.data.Employee
类的一个实例,然后显示结果。Arguments
对象的getInstance()
方法完成了调用Class.forName()
以及与正确调用请求类的构造函数进行协商的所有工作。
第16-18行
现在使用Arguments
对象收集Employee
实例中的所有数据,然后显示Arguments
对象。请注意,收集到Arguments
对象中的数据在元素顺序和类型上与Employee
类中声明的数据成员相匹配。
第20-24行
使用从Vector
类继承的setElementAt()
方法,将浮点值1,000设置为Arguments对象的第一个槽。接下来,Arguments
对象被命令隐藏所有运行时异常,并尝试调用Employee
实例的updateSalary()
方法。你可能已经猜到,我隐藏异常的原因是因为此时调用该方法会导致NoSuchMethodException
,因为Arguments对象当前包含的数据与updateSalary()
方法的签名不匹配。
第26-35行
可以查询Arguments
对象以查看最后一次方法调用是否导致了错误。由于我们知道确实发生了错误,所以我们现在移除不需要的数据,并尝试重新调用updateSalary()
方法,这次使用正确的值。为了证明薪资已正确提高,我再次显示Employee
实例。
演示应用程序的输出应该如下所示:创建实例 >> <Employee Name: [Doron, Barak], Age: [36], Salary: [3000.0]>
实例数据 >> [36, 3000.0, Doron, Barak]
错误:找不到类[dev.easyref.data.Employee]的方法 {
updateSalary(int p0, float p1, String p2, String p3);
}
调薪后 >> <Employee Name: [Doron, Barak], Age: [36], Salary: [4000.0]>
你可能已经注意到,尽管Arguments对象没有显示异常,但它确实报告了方法调用的不幸结果,并将错误消息发送到了System.err
流。
结论
下载代码,尽情使用吧。Java的反射是一个非常重要的工具,没有它,许多Java的特性将根本不存在。没有反射,你就无法使用复杂的IDE来设计GUI。你也无法使用序列化或RMI。
你可以在你的应用程序中使用Arguments
类本身,我只希望我有时间来正确地记录它。