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


2122

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

我对Java特别感兴趣,但是我认为原理在任何语言中都是相同的。


9
对我来说,这是一种在运行时获取类名称并创建该类的对象的方法。
纳宾

64
因为这是一个很普遍的问题,我想指出,反射(无注释)应该是解决问题时要使用的最后一个工具。我使用它并喜欢它,但是它抵消了Java静态类型的所有优点。如果确实需要,则将其隔离到尽可能小的区域(一个方法或一个类)。在测试中使用它比在生产代码中更可接受。使用注释应该没问题-如果可以避免的话,不要将类或方法的名称指定为“字符串”。
比尔K


4
除了@BillK的评论之外:反射非常强大,我称之为魔术。拥有权利的同时也被赋予了重大的责任。仅当您知道自己在做什么时才使用它。
MC Emperor

您可以使用歧管避免许多与反射有关的陷阱@Jailbreak。它提供对私有字段,方法等的直接,类型安全的访问。让Java编译器安全地验证您的代码,并让Manifold为您生成基础的反射访问。了解更多信息:歧管
斯科特,

Answers:


1716

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

例如,假设您在Java中有一个未知类型的对象,并且您想在该对象上调用“ doSomething”方法(如果存在)。除非对象符合已知的接口,否则Java的静态类型化系统并不是真正为支持该类型而设计的,但是使用反射,您的代码可以查看该对象并找出其是否具有名为“ doSomething”的方法,然后在需要时调用它想要。

因此,给您一个用Java编写的代码示例(假设有问题的对象是foo):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

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

有一些不错的反思示例,可帮助您入门:http://docs.oracle.com/javase/tutorial/reflect/index.html

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

来自评论的更新:

检查系统中的代码并查看对象类型的能力不是反射,而是类型自省。然后,反射就是利用自省功能在运行时进行修改的能力。这里的区别是必要的,因为某些语言支持自省,但不支持反射。C ++就是一个这样的例子。


32
您能否在这一行中说明该null参数的含义是什么?method method = foo.getClass()。getMethod(“ doSomething”,null);
Krsna Chaitanya '11

54
null表示没有参数传递给foo方法。有关详细信息,请参见docs.oracle.com/javase/6/docs/api/java/lang/reflect/…、java.lang.Object ...)。
马特·谢泼德

791
只是要清理一下,因为有很多投票。检查系统中的代码并查看对象类型的能力不是反射,而是类型自省。然后,反射就是利用自省功能在运行时进行修改的能力。此处的区别是必要的,因为某些语言支持自省,但不支持反射。C ++就是这样一个例子。
bigtunacan

39
我喜欢反射,但是如果您可以控制代码,则使用此答案中指定的反射是不必要的,因此是滥用的-您应使用Type Introspection(instanceof)和强类型。如果除了反思之外没有其他办法可以做某事,那就应该这样做。反射会导致严重的心痛,因为您失去了使用静态类型语言的所有优势。如果您需要它,则仍然需要它,但是即使如此,我仍会考虑使用诸如Spring之类的预包装解决方案或完全封装了必要的反射功能的IE:让其他人头疼。
Bill K

6
@bigtunacan您从何处获得该信息?我看到Oracle的官方Java文档中使用了“反射”一词,不仅描述了在运行时进行更改的能力,而且还描​​述了查看对象类型的能力。更何况,大多数所谓的“自省型”相关类(如:MethodConstructorModifierFieldMember,显然基本上所有除Class)是内java.lang.*reflect*包。也许“反射”概念全面包括“类型自省”和运行时修改?
RestInPeace 2016年

246

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

例如,Java中的所有对象都具有方法getClass(),即使您在编译时不知道该对象的类(例如,如果您将其声明为Object),也可以让您确定该对象的类-这似乎很简单,但是这种反射是不可能的用不太活跃的语言如C++。更高级的用法使您可以列出和调用方法,构造函数等。

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

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


2
因此,换句话说,您可以使用其限定名称创建实例,并且编译器不会抱怨它(因为说您仅使用String作为类名)。然后,在运行时,如果该类不存在,则会出现异常。在这种情况下,您有点绕过了编译器。您能给我一些具体的用例吗?当我选择它时,我只是无法想象。
费尔南多·加布里埃利

3
@FernandoGabrieli确实很容易通过反射创建运行时错误,但是使用反射也很可能不会冒运行时异常的危险。正如我的回答所暗示的,反射的常见用法是用于库或框架,因为库或框架是与应用程序分开编译的,所以它们在编译时显然无法了解应用程序的结构。使用“按惯例编码”的任何库都可能使用反射,但不一定使用魔术字符串。
Liedman '19

C++确实具有运行时类型信息。RTTI
艾肯(Ayxan)

114

我最喜欢的反射用法之一是下面的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();
}

8
Callcount应该设置为什么?
汤姆(Tom)2010年

8
当我运行此线程时,线程“ AWT-EventQueue-0” java.lang.StackOverflowError中出现异常。
汤姆(Tom)2010年

3
@Tom callCount应该设置为零。它的值用于确定输出的每一行之前应有多少个制表符:每次转储需要转储“子对象”时,输出将作为嵌套在父项中打印。将该方法包裹在另一个方法中证明是有用的。考虑一下printDump(Object obj){ System.out.println(dump(obj, 0)); }
2012年

1
由于未经检查的递归,可能在循环引用的情况下创建java.lang.StackOverflowError:buffer.append(dump(value,callCount))
Arnaud P

4
能否请您将代码专门发布到Public Domain,好吗?
stolsvik

84

反射的用途

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

扩展功能

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

反思的缺点

反射功能强大,但不应任意使用。如果可以在不使用反射的情况下执行操作,那么最好避免使用它。通过反射访问代码时,应牢记以下注意事项。

  • 绩效开销

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

  • 安全限制

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

  • 内部暴露

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

来源:Reflection API


44

反射是一种允许应用程序或框架使用甚至尚未编写的代码的关键机制!

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

另一个示例是用于XML解析的Java API (JAXP)。通过众所周知的系统属性“插入” XML解析器提供程序的位置,该属性用于通过反射构造新实例。

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


36

并非每种语言都支持反射,但是支持反射的语言的原理通常是相同的。

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

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


我需要基于数据库中存在的数据实例化对象。我相信这就是您的意思。示例代码对我有很大帮助。提前致谢。
Atom 2015年

34

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

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,但是如果使用过多,它可能会使应用程序变慢,因为它可以在运行时解析所有类型。


21

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

一个简单的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>元素时,它将使用带有参数“ com.example.Foo”的Class.forName(String)实例化该Class。

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

  • Junit特别使用反射来测试专用/受保护的方法。

对于私有方法,

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

21

例:

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

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

因此,我们可以在3个类中实现,每个类包含不同的逻辑。显然,对象信息在运行时可用,因此您不能静态地执行代码,因此反射被用来实例化基于对象进行计算所需的类的对象。从提供者收到的对象。


我需要类似的东西..一个例子就是帮了我很多,因为我是新来的反射概念..

2
我很困惑:您不能instanceof在运行时用来确定对象类型吗?
ndm13

19

反映的简单示例。在国际象棋游戏中,您不知道用户在运行时将移动什么。反射可用于调用在运行时已实现的方法:

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

}

18

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

  1. 在下提供了所需的反射类java.lang.reflect package
  2. 反射为我们提供了有关对象所属类的信息,以及可以使用该对象执行的该类的方法。
  3. 通过反射,我们可以在运行时调用方法,而与它们所使用的访问说明符无关。

java.langjava.lang.reflect包Java反射提供类。

反射可用于获取有关–的信息

  1. getClass()方法用于获取对象所属的类的名称。

  2. 构造函数getConstructors()方法用于获取对象所属类的公共构造函数。

  3. 方法getMethods()方法用于获取对象所属类的公共方法。

反射API主要用于:

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

使用反射的优势:

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

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

缺点:

性能开销:反射操作比非反射操作的性能要慢,应避免在对性能敏感的应用程序中经常调用的代码部分中将其避免。

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

参考:Java Reflection javarevisited.blogspot.in


4
我会增加缺点“ 它破坏了重构 ”。对我来说,这是尽可能避免反射的主要原因。
SantiBailors

因此,它允许我们(例如)检查我们拥有的类(是否具有它们的实例),对吗?我的意思是,获取它们的方法或构造函数,并使用它们创建新的实例/调用它们。如果行为已经存在但使用不同的代码,为什么我们说“更改程序行为”?为什么称为“反射”?谢谢
费尔南多·加布里埃利

15

根据我的理解:

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

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

相反,通过使用反射,需要担心类名称可能会更改。


15

反射是一组功能,使您可以访问程序的运行时信息并修改其行为(有一些限制)。

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

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

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


11

我只想向列出的所有内容添加一些要点。

使用Reflection 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;
   }    
}

11

反射是让物体看到它们的外观。这种说法似乎与反思无关。实际上,这就是“自我识别”能力。

反射本身就是这类语言的缩写,因为它们缺乏像Java和C#这样的自我知识和自我感知能力。因为他们没有自我认识的能力,所以当我们要观察它的外观时,我们必须有另一件事来反思它的外观。优秀的动态语言(例如Ruby和Python)无需其他人的帮助即可感知自己的反映。我们可以说Java对象不能在没有镜像的情况下感知它的外观,而镜像是反射类的对象,但是Python中的对象可以在没有镜像的情况下感知它。因此,这就是为什么我们需要在Java中进行反思。


type(),isinstance(),callable(),dir()和getattr()。....这些是
pythonic

9

从Java文档页面

java.lang.reflect包提供用于获取有关类和对象的反射信息的类和接口。通过反射,可以在安全性限制内以编程方式访问有关已加载类的字段,方法和构造函数的信息,并可以使用反射的字段,方法和构造函数对其基础副本进行操作。

AccessibleObject如果有必要,ReflectPermission则允许禁止访问检查。

类此包,伴随着java.lang.Class适应应用,如调试器,口译,目标督察,类浏览器,以及诸如服务Object SerializationJavaBeans(基于其运行时类)需要访问到任何一个目标对象的公共成员或成员宣布给定的班级

它包括以下功能。

  1. 获取Class对象,
  2. 检查类的属性(字段,方法,构造函数),
  3. 设置和获取字段值
  4. 调用方法
  5. 创建对象的新实例。

请查看此文档链接,以了解Class类公开的方法。

本文(Sosnoski Software Solutions,Inc.总裁Dennis Sosnoski)和本文(安全性探索pdf)开始:

与使用反射相比,我可以看到很多弊端

反射用户:

  1. 它提供了非常通用的动态链接程序组件的方式
  2. 这对于创建以非常通用的方式使用对象的库很有用

反思的缺点:

  1. 当用于字段和方法访问时,反射比直接代码慢得多。
  2. 它可以掩盖代码内部的实际情况
  3. 它绕过源代码会造成维护问题
  4. 反射代码也比相应的直接代码复杂
  5. 它允许违反关键的Java安全约束,例如数据访问保护和类型安全

一般滥用行为:

  1. 加载受限类,
  2. 获取对受限类的构造函数,方法或字段的引用,
  3. 创建新的对象实例,方法调用,获取或设置受限类的字段值。

看一下有关反射功能滥用的SE问题:

如何在Java中读取私有字段?

摘要:

从系统代码中不安全地使用其功能也很容易导致Java安全模式的妥协因此,请谨慎使用此功能


在某些情况下,避免Reflection性能问题的一种方法是,让一个Woozle类在启动时检查其他类,以查看哪些类具有静态RegisterAsWoozleHelper()方法,并使用可用于告知Woozle自己的回调调用它找到的所有此类方法,从而避免在反序列化数据时需要使用Reflection。
supercat


7

反射使您能够编写更多通用代码。它允许您在运行时创建对象并在运行时调用其方法。因此,可以使程序高度参数化。它还允许自省对象和类以检测暴露给外部世界的变量和方法。


6

Reflection有很多用途。我比较熟悉的一种功能是能够即时创建代码。

IE:动态类,函数,构造函数-基于任何数据(xml / array / sql结果/ hardcoded /等)。


1
这个答案将是好了很多,如果你从一个SQL结果或XML文件等给了生成的代码只是一个不寻常的例子要么
ThisClark

没问题。我在Windows应用程序中使用了反射,该应用程序根据从数据库获取的XML动态生成接口。
Ess Kay

因此,基本上,我创建了一个向用户显示报告的类。此报告具有诸如Date(from)的参数,或其他任何参数。此信息存储在xml中。因此,首先我们有一个报告选择。根据选择的报告,表单获取xml。检索到xml后,它将使用反射创建具有基于反射类型的字段的类。更改为其他报告后,将清除所有记录,并基于xml生成新字段。因此,它本质上是基于反射的动态形式。我也以其他方式使用过,但这应该足够,希望会有所帮助
Ess Kay

3

我想举例说明这个问题。首先,Hibernate项目使用Reflection API生成CRUD语句来桥接正在运行的应用程序和持久性存储之间的鸿沟。当领域中的事物发生变化时,Hibernate必须了解它们以将其持久保存到数据存储中,反之亦然。

另一种方法Lombok Project。它只是在编译时注入代码,导致代码被插入到您的域类中。(我认为对getter和setter来说还可以)

Hibernate选择reflection它是因为它对应用程序的构建过程影响最小。

从Java 7开始MethodHandles,它具有的功能Reflection API。在项目中,要与记录器一起使用,我们只需复制粘贴以下代码:

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

因为在这种情况下很难犯错字。


3

我发现最好通过示例进行解释,但似乎没有答案可以解决这个问题。

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.