通过阅读一些文章,我得到的信息是能够在实时环境下修改字段并为类设置值,而无需重新编译。
那么,是否可以对没有源代码可用的第三方Java库创建的类进行此操作?或者说,是否可以使用反射来修改运行时类实例?
反射在哪些其他场景中常被使用?
我正在尝试理解反射如何适用。
通过阅读一些文章,我得到的信息是能够在实时环境下修改字段并为类设置值,而无需重新编译。
那么,是否可以对没有源代码可用的第三方Java库创建的类进行此操作?或者说,是否可以使用反射来修改运行时类实例?
反射在哪些其他场景中常被使用?
我正在尝试理解反射如何适用。
java com.example.MyClass
将一个字符串转换为类名。这不需要反射,因为java
可执行文件可以将.class
文件转换为代码,但是如果没有反射,就无法编写像java com.example.Wrapper com.example.MyClass
这样的代码,其中Wrapper
委托给其参数,如下所示:class Wrapper {
public static void main(String... argv) throws Exception {
// Do some initialization or other work.
Class<?> delegate = Class.forName(argv[0]);
Method main = delegate.getMethod("main", String[].class);
main.apply(null, Arrays.asList(argv).subList(1, argv.length).toArray(argv));
}
}
另一个案例是开发类似于eclipse/netbeans等IDE的工具,以确定抽象类中哪些方法需要由子类实现,并自动为您编写缺失的方法调用(例如之一)。
我被要求为以下陈述创建一个解决方案。
"1)一个差异服务,它: • 可以计算两个对象之间的差异并返回结果 • 可以对原始对象应用先前创建的“diff”,以便返回的对象与用于计算差异的修改后的对象相匹配。"
如果没有使用反射,这将非常困难。使用反射,我可以列出所有未知对象的类元素、属性和方法。我可以使用这些来获取对象中包含的值。我可以比较原始和修改后的对象的值,创建“diff”对象反映两个对象之间的更改。
使用Java反射,我可以读取“diff”对象中的指令,并将其应用于原始对象。Java反射为我提供了改变原始对象的未知属性值所需的工具。我可以调用setter方法并实例化类型(如果原始属性为空),以在原始对象上设置修改后的值。
“diff”应用程序适用于任何两个相同类型的对象,但它们可以是任何类型,只要两个对象是相同类型即可。
反射是非常强大的,它允许我们创建真正的通用多态方法、函数、库和系统,在这些情况下,传递的对象类型不需要在编译时知道。当使用Java反射和泛型结合时,这种能力变得更加强大。
最后,我还使用Java反射创建了一个通用的排序函数,可以对任何类类型的列表进行排序,使用类的任何属性作为排序键。只要调用方法传递了列表和要使用的属性名称,该方法就会返回一个已排序的列表。
反射在需要配置来串联事物的情况下也非常有用。例如,在我编写的一个应用程序中,我有一个@Report("debits")注释,只需添加到生成报告的方法中即可。然后,在XML配置中,用户可以简单地添加:
<requiredReports="debits,blah,another"/>
这样可以最小化从映射XML代码到实际方法的样板代码,因为反射可以发现报告方法并直接使其可用。
以下是一些使用反射的情况
public class Main {
public static void main(String[] args) {
displayProperties(Stage.class);
}
public static void displayProperties(Class class) {
boolean hasParam = false;
boolean hasReturn = false;
ArrayList<Method> propMethods = new ArrayList<>();
Method[] methods = clazz.getMethods();
for (Method m: methods) {
Parameter[] paraType = m.getParameters();
if(m.getParameterCount()<2) {
if ((m.getReturnType() == void.class && paraType.length == 1) || (m.getReturnType() != void.class && paraType.length == 0)) {
//Get the properties alone
propMethods.add(m);
}
}
}
for (int i = 0; i < propMethods.size(); i++) {
if (propMethods.get(i).getName().startsWith("get") || propMethods.get(i).getName().startsWith("set")) {
System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName().substring(3)+"( "+propMethods.get(i).getReturnType().getTypeName()+" )");
} else
System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName() + "( "+propMethods.get(i).getReturnType().getTypeName()+" )");
}
}
public static String readWrite(Method method, ArrayList<Method> propMeths) {
ArrayList<Method> temp;
temp = propMeths;
boolean readIn = false;
boolean writeIn = false;
String onlyName = method.getName().substring(3);
for (int i = 0; i < temp.size(); i++) {
//use the substring--
if (temp.get(i).getName().startsWith("get") && temp.get(i).getName().endsWith(onlyName)) {
readIn = true;
}
if (temp.get(i).getName().startsWith("set") && temp.get(i).getName().endsWith(onlyName)) {
writeIn = true;
}
}
if (readIn == true && writeIn == true)
return "rw ";
else if (readIn == true && writeIn == false)
return "r ";
else
return "w ";
}
}
String类的另一个案例
public static void main(String[] args)
{
displayProperties(String.class);
}
public static void displayProperties(Class class){
clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();
for(int ii = 0; ii<methods.length; ii++){
System.out.println("Method Name: "+methods[ii].getName());
System.out.println("Method Type: "+methods[ii].getReturnType());
System.out.println("Method Pa: "+methods[ii].getParameterCount());
System.out.println("Method Type: "+methods[ii].getReturnType());
}
}
使用反射从XML加载
public static Object loadFromXml(String filePath) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
File newFile = new File(filePath);
Document doc = builder.parse(newFile);
Node root = doc.getFirstChild();
return loadObjectElement(root);
}
/**
* This method loads from an xml file and returns all the contents of the file as an object
* @param root The node passed in to the method from which the "tree" gets a new level
* @return all the contents of the xml file as an object
* @throws Exception
*/
public static Object loadObjectElement(Node root) throws Exception {
//loads the root
String studentClass = root.getAttributes().getNamedItem("class").getTextContent();
Object newStudentObject = Class.forName(studentClass).newInstance();
//gets the children nodes (may have text elements like \n)
NodeList studentFieldList = root.getChildNodes();
//iterates through the children nodes
for (int i = 0; i < studentFieldList.getLength(); i++) {
//checks to make sure the child node is not a text node
if (studentFieldList.item(i).getNodeType() != Node.TEXT_NODE) {
//checks if the current node does not have children
if (studentFieldList.item(i).getChildNodes().getLength() == 0) {
//receives data of the current node
String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
String valueField = studentFieldList.item(i).getAttributes().getNamedItem("value").getTextContent();
Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);
//makes the field accessible
declaredFieldInClass.setAccessible(true);
//checks the field type
switch (declaredFieldInClass.getType().getSimpleName().toLowerCase()) {
case "integer":
case "int":
declaredFieldInClass.set(newStudentObject, Integer.valueOf(valueField));
break;
case "float":
declaredFieldInClass.set(newStudentObject, Float.valueOf(valueField));
break;
case "boolean":
declaredFieldInClass.set(newStudentObject, Boolean.valueOf(valueField));
break;
default:
declaredFieldInClass.set(newStudentObject, valueField);
}
declaredFieldInClass.setAccessible(false);
} else {
//there are children in the current node
NodeList modulesObjectList = studentFieldList.item(i).getChildNodes();
String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);
List<Object> modules = new ArrayList<>();
//adds the modules into the array
for (int j = 0; j < modulesObjectList.getLength(); j++) {
if (modulesObjectList.item(j).getNodeType() != Node.TEXT_NODE) {
//recursively calls the the loadObjectElement method for any sub lists
modules.add(loadObjectElement(modulesObjectList.item(j)));
}
}
//sets the modules of the specific student that the method is working with
declaredFieldInClass.set(newStudentObject, modules);
}
}
}
return newStudentObject;
}