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

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


当前回答

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

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

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

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

其他回答

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

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

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

根据我的理解:

反射允许程序员动态访问程序中的实体。也就是说,当程序员对应用程序进行编码时,如果不知道类或其方法,他可以通过使用反射来动态地(在运行时)使用此类类。

它经常用于类名频繁更改的场景。如果出现这种情况,那么程序员重写应用程序并一次又一次地更改类的名称是很复杂的。

相反,通过使用反射,需要担心类名可能会发生变化。

Java反射非常强大,非常有用。Java反射使得在运行时检查类、接口、字段和方法成为可能,而不需要在编译时知道类、方法等的名称。还可以使用反射实例化新对象、调用方法和获取/设置字段值。

一个快速的Java反射示例,向您展示使用反射的样子:

Method[] methods = MyObject.class.getMethods();

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }

此示例从名为MyObject的类中获取Class对象。该示例使用类对象获取该类中方法的列表,迭代方法并打印出它们的名称。

这里解释了这一切的确切原理

编辑:差不多一年后,我在编辑这个答案,因为在阅读反思时,我很少再使用反思。

Spring使用bean配置,例如:

<bean id="someID" class="com.example.Foo">
    <property name="someField" value="someValue" />
</bean>

当Spring上下文处理这个<bean>元素时,它将使用Class.forName(String)和参数“com.example.Foo”来实例化该Class。

然后,它将再次使用反射为<property>元素获取适当的setter,并将其值设置为指定值。

Junit特别使用Reflection来测试Private/Protected方法。

对于私有方法,

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

对于私人领域,

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

反射允许在运行时动态实例化新对象、调用方法和获取/设置类变量的操作,而无需事先了解其实现。

Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();

//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class); 

Object returnValue = method.invoke(null, "parameter-value1");

在上面的示例中,null参数是要对其调用方法的对象。如果方法是静态的,则提供null。如果该方法不是静态的,那么在调用时需要提供有效的MyObject实例而不是null。

反射还允许您访问类的私有成员/方法:

public class A{

  private String str= null;

  public A(String str) {
  this.str= str;
  }
}

.

A obj= new A("Some value");

Field privateStringField = A.class.getDeclaredField("privateString");

//Turn off access check for this field
privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);

为了检查类(也称为内省),不需要导入反射包(java.lang.reflect)。可以通过java.lang.Class访问类元数据。

反射是一个非常强大的API,但如果过度使用,它可能会降低应用程序的速度,因为它在运行时解析所有类型。

反射是一种API,用于在运行时检查或修改方法、类和接口的行为。

反射所需的类在java.lang.reflect包中提供。反射为我们提供了有关对象所属的类的信息,以及可以使用该对象执行的该类的方法。通过反射,我们可以在运行时调用方法,而不考虑与它们一起使用的访问说明符。

java.lang和java.lang.reflect包为java反射提供了类。

反射可用于获取以下信息:

类getClass()方法用于获取对象所属类的名称。构造函数getConstructors()方法用于获取对象所属类的公共构造函数。方法getMethods()方法用于获取对象所属类的公共方法。

反射API主要用于:

IDE(集成开发环境),例如Eclipse、MyEclipse、NetBeans等。调试器和测试工具等。

使用反射的优点:

可扩展性特性:应用程序可以通过使用扩展性对象的完全限定名称创建扩展性对象实例来使用外部用户定义的类。

调试和测试工具:调试器使用反射属性来检查类上的私有成员。

缺点:

性能开销:反射操作的性能低于非反射操作,应避免在性能敏感应用程序中频繁调用的代码段中使用。

内部暴露:反射代码打破了抽象,因此可能会随着平台的升级而改变行为。

参考:Java Reflection javareviewed.blogspot.in