Java 什么是反射,为什么它有用?

Java 什么是反射,为什么它有用?,java,reflection,terminology,Java,Reflection,Terminology,什么是反射,为什么它有用 我对Java特别感兴趣,但我认为任何语言的原理都是一样的。名称反射用于描述能够检查同一系统(或自身)中其他代码的代码 例如,假设您在Java中有一个未知类型的对象,如果存在,您希望对其调用“doSomething”方法。Java的静态类型系统并不是真正设计来支持这一点的,除非对象符合已知的接口,但是使用反射,您的代码可以查看对象并找出它是否有一个名为“doSomething”的方法,如果您愿意,可以调用它 因此,给您一个Java中的代码示例(假设所讨论的对象是foo):

什么是反射,为什么它有用


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

名称反射用于描述能够检查同一系统(或自身)中其他代码的代码

例如,假设您在Java中有一个未知类型的对象,如果存在,您希望对其调用“doSomething”方法。Java的静态类型系统并不是真正设计来支持这一点的,除非对象符合已知的接口,但是使用反射,您的代码可以查看对象并找出它是否有一个名为“doSomething”的方法,如果您愿意,可以调用它

因此,给您一个Java中的代码示例(假设所讨论的对象是foo):

Java中一个非常常见的用例是注释的使用。例如,JUnit4将使用反射在类中查找带有@Test注释的方法,然后在运行单元测试时调用它们

有一些很好的反射示例可以让您开始学习

最后,是的,这些概念在其他支持反射的静态类型语言(如C#)中非常相似。在动态类型语言中,上面描述的用例不太必要(因为编译器将允许对任何对象调用任何方法,如果该对象不存在,则在运行时失败),但是第二种情况仍然很常见,即查找标记了的方法或以某种方式工作的方法

根据评论更新:

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

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }
检查系统中的代码并查看对象类型的能力是 不是反思,而是类型的内省。因此,反射是最重要的 能够在运行时通过使用 反省这种区别在这里是必要的,因为有些语言 支持内省,但不支持反思。一个这样的例子 是C吗++


反射是一组函数,允许您访问程序的运行时信息并修改其行为(有一些限制)

它很有用,因为它允许您根据程序的元信息更改运行时行为,也就是说,您可以检查函数的返回类型并更改处理情况的方式

例如,在C#中,您可以在运行时加载程序集(a.dll)并对其进行检查,在类中导航并根据发现的内容采取操作。它还允许您在运行时创建类的实例,调用其方法,等等


它在哪里有用?不是每次都有用,只是在具体情况下有用。例如,您可以使用它获取用于日志记录的类的名称,根据配置文件上指定的内容动态创建事件处理程序等等…

并非所有语言都支持反射,但支持反射的语言中的原则通常是相同的

反思是对程序结构进行“反思”的能力。或者更具体。查看您拥有的对象和类,并以编程方式获取有关它们实现的方法、字段和接口的信息。您还可以查看注释之类的内容

它在很多情况下都很有用。您希望在任何地方都能将类动态插入到代码中。许多对象关系映射程序使用反射来实例化数据库中的对象,而不必事先知道要使用什么对象。插件体系结构是反射有用的另一个地方。在这些情况下,能够动态加载代码并确定是否存在实现正确接口作为插件使用的类型非常重要


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

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

反射很重要,因为它让您编写的程序不必在编译时“了解”所有内容,从而使它们更具动态性,因为它们可以在运行时绑定在一起。代码可以针对已知接口编写,但要使用的实际类可以使用配置文件的反射进行实例化


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

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

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

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


最后,最全面的例子是使用反射创建bean,由于大量使用代理,我最喜欢的反射用法之一是下面的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();
}
import java.lang.reflect.Array;
导入java.lang.reflect.Field;
公共静态字符串转储(对象o,int callCount){
callCount++;
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");
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);
Method[] methods = MyObject.class.getMethods();

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }
<bean id="someID" class="com.example.Foo">
    <property name="someField" value="someValue" />
</bean>
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 ObjectAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}
public class Test {

    public void firstMoveChoice(){
        System.out.println("First Move");
    } 
    public void secondMOveChoice(){
        System.out.println("Second Move");
    }
    public void thirdMoveChoice(){
        System.out.println("Third Move");
    }

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
        Test test = new Test();
        Method[] method = test.getClass().getMethods();
        //firstMoveChoice
        method[0].invoke(test, null);
        //secondMoveChoice
        method[1].invoke(test, null);
        //thirdMoveChoice
        method[2].invoke(test, null);
    }

}
Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());