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

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


当前回答

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

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,您可以为任何对象编写通用的toString()方法。

它可能对调试有用。

以下是一些示例:

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

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

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

例如,在C#中,您可以在运行时加载程序集(.dll)并检查它,浏览类并根据找到的内容执行操作。它还允许您在运行时创建类的实例,调用其方法等。

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

反射的使用

反射通常由需要检查或修改在Java虚拟机中运行的应用程序的运行时行为的程序使用。这是一个相对高级的特性,只有对语言基础有很强理解的开发人员才能使用。考虑到这一点,反射是一种强大的技术,可以使应用程序执行不可能执行的操作。

可扩展性功能

应用程序可以通过使用扩展性对象的完全限定名称创建扩展性对象实例来使用外部用户定义的类。类浏览器和可视化开发环境类浏览器需要能够枚举类的成员。可视化开发环境可以受益于利用反射中可用的类型信息来帮助开发人员编写正确的代码。调试器和测试工具调试器需要能够检查类中的私有成员。测试工具可以利用反射来系统地调用类上定义的可发现集合API,以确保测试套件中的代码覆盖率较高。

反射的缺点

反射是强大的,但不应滥用。如果可以在不使用反射的情况下执行一个操作,那么最好避免使用它。

性能开销

由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。因此,反射操作的性能比非反射操作慢,应该避免在性能敏感应用程序中频繁调用的代码段中使用。

安全性限制

反射需要在安全管理器下运行时可能不存在的运行时权限。对于必须在受限安全上下文(如Applet)中运行的代码,这是一个重要的考虑因素。

内部构件暴露

由于反射允许代码执行在非反射代码中非法的操作,例如访问私有字段和方法,因此使用反射可能会导致意外的副作用,这可能会导致代码功能失调,并可能破坏可移植性。反射代码打破了抽象,因此可能会随着平台的升级而改变行为。

来源:反射API

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

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

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

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

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

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