什么是反思,为什么它有用?

我对Java特别感兴趣,但我认为任何语言的原理都是一样的。


当前回答

反射有很多用途。我更熟悉的是能够动态创建代码。

IE:基于任何数据的动态类、函数、构造函数(xml/array/sql results/hardcoded/etc.)

其他回答

反射是一种语言在运行时检查和动态调用类、方法、属性等的能力。

例如,Java中的所有对象都有getClass()方法,该方法允许您确定对象的类,即使您在编译时不知道它(例如,如果您将其声明为object)-这可能看起来微不足道,但这种反射在动态性较差的语言(如C++)中是不可能的。更高级的用法允许您列出和调用方法、构造函数等。

反射是很重要的,因为它让你编写的程序不必在编译时“知道”一切,使它们更加动态,因为它们可以在运行时绑定在一起。代码可以针对已知的接口编写,但要使用的实际类可以使用配置文件的反射来实例化。

出于这个原因,许多现代框架广泛使用反射。大多数其他现代语言也使用反射,在脚本语言(如Python)中,它们甚至更紧密地集成在一起,因为在这些语言的通用编程模型中感觉更自然。

例子:

以一个远程应用程序为例,它为您的应用程序提供了一个对象,您可以使用其API方法获取该对象。现在,基于对象,您可能需要执行某种计算。

提供者保证对象可以是3种类型,我们需要根据对象的类型进行计算。

因此,我们可以在3个类中实现,每个类包含不同的逻辑。显然,对象信息在运行时可用,因此您无法静态编码以执行计算,因此反射用于实例化类的对象,您需要根据从提供程序接收的对象执行计算。

反射是允许应用程序或框架处理可能尚未编写的代码的关键机制!

以典型的web.xml文件为例。这将包含一个servlet元素列表,其中包含嵌套的servlet类元素。servlet容器将处理web.xml文件,并通过反射创建每个servlet类的新实例。

另一个例子是Java API for XML Parsing(JAXP)。其中,XML解析器提供程序是通过众所周知的系统财产“插入”的,这些属性用于通过反射构造新实例。

最后,最全面的例子是Spring,它使用反射创建bean,并大量使用代理

我觉得最好用例子来解释,但没有一个答案能做到这一点。。。

使用反射的一个实际例子是用Java编写的Java语言服务器或用PHP编写的PHP语言服务器等。语言服务器为您的IDE提供自动完成、跳转到定义、上下文帮助、提示类型等功能。为了让所有标记名(可以自动完成的单词)在键入时显示所有可能的匹配项,语言服务器必须检查类的所有内容,包括文档块和私有成员。为此,它需要对所述阶级的反思。

另一个例子是私有方法的单元测试。这样做的一种方法是创建一个反射,并在测试的设置阶段将方法的范围更改为公开。当然,有人会认为不应该直接测试私有方法,但这不是重点。

我最喜欢的反射用法之一是下面的Java转储方法。它将任何对象作为参数,并使用Java反射API打印出每个字段名和值。

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o, int callCount) {
    callCount++;
    StringBuffer tabs = new StringBuffer();
    for (int k = 0; k < callCount; k++) {
        tabs.append("\t");
    }
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
    if (oClass.isArray()) {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            if (i < 0)
                buffer.append(",");
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class
                    ) {
                buffer.append(value);
            } else {
                buffer.append(dump(value, callCount));
            }
        }
        buffer.append(tabs.toString());
        buffer.append("]\n");
    } else {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                buffer.append(tabs.toString());
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value, callCount));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append(tabs.toString());
        buffer.append("}\n");
    }
    return buffer.toString();
}