Java:什么情况下需要使用反射?

14

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

那么,是否可以对没有源代码可用的第三方Java库创建的类进行此操作?或者说,是否可以使用反射来修改运行时类实例?

反射在哪些其他场景中常被使用?

我正在尝试理解反射如何适用。

6个回答

16
任何时候当你在运行时处理字符串并且想要将该字符串的一部分作为语言中的标识符来处理时,
  1. 远程过程调用——将从网络接收到的消息的一部分作为方法名来处理。
  2. 序列化和反序列化——将字段名称转换为字符串,以便可以将对象的字段写入流,然后将其转换回对象。
  3. 对象关系映射——在对象的字段和数据库中的列之间保持关联。
  4. 与动态类型脚本语言的接口——将脚本语言生成的字符串值转换为字段或对象上的方法的引用。
它还可用于允许在语言中模拟语言特性。例如,考虑命令行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));
  }
}

3

另一个案例是开发类似于eclipse/netbeans等IDE的工具,以确定抽象类中哪些方法需要由子类实现,并自动为您编写缺失的方法调用(例如之一)。


2

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


0

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

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

如果没有使用反射,这将非常困难。使用反射,我可以列出所有未知对象的类元素、属性和方法。我可以使用这些来获取对象中包含的值。我可以比较原始和修改后的对象的值,创建“diff”对象反映两个对象之间的更改。

使用Java反射,我可以读取“diff”对象中的指令,并将其应用于原始对象。Java反射为我提供了改变原始对象的未知属性值所需的工具。我可以调用setter方法并实例化类型(如果原始属性为空),以在原始对象上设置修改后的值。

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

反射是非常强大的,它允许我们创建真正的通用多态方法、函数、库和系统,在这些情况下,传递的对象类型不需要在编译时知道。当使用Java反射和泛型结合时,这种能力变得更加强大。

最后,我还使用Java反射创建了一个通用的排序函数,可以对任何类类型的列表进行排序,使用类的任何属性作为排序键。只要调用方法传递了列表和要使用的属性名称,该方法就会返回一个已排序的列表。


0

反射在需要配置来串联事物的情况下也非常有用。例如,在我编写的一个应用程序中,我有一个@Report("debits")注释,只需添加到生成报告的方法中即可。然后,在XML配置中,用户可以简单地添加:

<requiredReports="debits,blah,another"/>

这样可以最小化从映射XML代码到实际方法的样板代码,因为反射可以发现报告方法并直接使其可用。


0

以下是一些使用反射的情况

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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接