Java:什么场景要求使用reflection?

因此,通过阅读一些文章,我得到的消息是能够实时修改字段并将值设置为类,而无需重新编译。

那么有可能这样做到第三方java库创建的类没有源代码可用/是否可以使用reflection在运行时修改类实例?

在其他场景中常用的reflection是什么?

我试图理解reflection是如何适用的。

每次在运行时处理字符串并希望将该字符串的一部分视为语言中的标识符。

  1. 远程过程调用 – 将通过网络接收的消息的一部分视为方法名称。
  2. 序列化和反序列化 – 将字段名称转换为字符串,以便您可以将对象的字段写入流,然后将其转换回对象。
  3. 对象关系映射 – 维护对象中的字段与数据库中的列之间的关系。
  4. 与动态类型脚本语言的接口 – 将脚本语言生成的字符串值转换为对象上的字段或方法的引用。

它还可用于允许在语言中模拟语言function。 考虑命令行java com.example.MyClass ,它将字符串转换为类名。 这不需要reflection,因为java可执行文件可以将.class文件转换为代码,但是如果没有reflection,它将无法编写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)); } } 

开发IDE(如eclipse / netbeans等)的另一种情况是确定抽象类中的哪些方法需要由子类实现,并自动为您编写缺少的方法调用(一个示例)。

当需要进入classes in deeper level的其他classes in deeper level时,使用reflection 。 因此在大多数情况下,这些实现者都具有容器行为。 例如,dependency injection主要通过使用reflection来完成。 如果您需要一个框架作为示例,Spring会在reflection API的帮助下完成其dependency injection作业。

您还可以在许多区域中找到幕后使用的reflection。 例如,如果您使用了JAXB,那么XML的许多编组/解组都将使用reflection来完成。 在代码中使用注释通常会导致在幕后使用reflection。 在执行unit testing时,特别是在模拟类和/或方法时,通常会使用大量的reflection代码。

像Guice或Spring这样的注入框架使用reflection来帮助您在运行时构建对象的实例。

在需要配置将事物串在一起的情况下,reflection也很有用。 例如,在我写的应用程序中,我有一个@Report(“debits”)注释,它只是添加到生成报告的方法中。 然后,在XML配置中,用户可以简单地添加:

  

这样可以最大限度地减少锅炉板代码将XML代码映射到实际方法,因为reflection可以发现报告方法并使其直接可用。

我被要求为以下声明创建一个解决方案。

“1)差异服务:•可以计算两个对象之间的差异并返回结果”差异“•可以对原始对象应用先前创建的”差异“,以便返回的对象与以前修改的对象匹配计算差异。“

如果不使用reflection,这将是非常困难的。 使用reflection我可以列出所有未知对象的Class元素,属性和方法。 我可以使用它们来获取对象中包含的值。 我可以比较原始和修改的对象值,创建反映两个对象之间变化的“diff”对象。

使用Javareflection,然后我可以读取“diff”对象中的指令并将它们应用于原始对象。 Javareflection为我提供了更改原始对象的未知属性值所需的工具。 如果原始属性为null,我可以调用setter方法并在需要时实例化类型,以在原始对象上设置修改后的值。

“diff”应用程序适用于任何两个相同类型的对象,但它们可以是任何类型,两个对象只需要具有相同的类型。

reflection非常强大,允许我们创建真正的通用多态方法,函数,库和系统,其中传递的对象类型不需要在编译时知道。 这在将Java Reflection和Generics结合使用时非常有用,这是一个非常强大的组合。

为了结束,我还使用Java Reflection创建了一个generics排序函数,它可以使用Class的任何属性作为排序键对任何类类型的任何列表进行排序。只要调用方法传递了列表和属性要使用的名称,该方法将返回一个排序列表。

以下是一些使用reflection的情况

 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 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 propMeths) { ArrayList 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 

使用reflection从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 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; }