ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

对我来说,这是一种在运行时获取类名并创建该类对象的方法。
因为这是一个流行的问题,所以我想指出反射(没有注释)应该是您解决问题时使用的最后一个工具。我使用它并且喜欢它,但它抵消了 Java 静态类型的所有优点。如果您确实需要它,请将其隔离到尽可能小的区域(一个方法或一个类)。在测试中使用它比在生产代码中使用它更容易接受。使用注释应该没问题 - 如果可以避免的话,重点是不要将类或方法名称指定为“字符串”。
除了@BillK 的评论:反射非常强大,我称之为魔法。拥有权利的同时也被赋予了重大的责任。仅当您知道自己在做什么时才使用它。
@Trap我不知道,这就是我建议反对它的原因——当我遇到其他可用解决方案时的反思时,或者反思不是孤立于一个非常小的、受限且清晰记录的区域时,这真的很烦人代码。但是问程序员为什么要做他们所做的事情超出了我的回答能力。

M
Marome

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

例如,假设您在 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++


你能解释一下这一行中那个空参数的意义吗 Method method = foo.getClass().getMethod("doSomething", null);
null 表示没有参数传递给 foo 方法。有关详细信息,请参见 docs.oracle.com/javase/6/docs/api/java/lang/reflect/…,java.lang.Object...)。
只是为了澄清,因为这有很多赞成票。检查系统中的代码并查看对象类型的能力不是反射,而是类型自省。然后,反射是通过使用自省在运行时进行修改的能力。这里有必要进行区分,因为某些语言支持自省,但不支持反射。一个这样的例子是 C++。
我喜欢反射,但如果你可以控制代码,那么使用这个答案中指定的反射是不必要的,因此是一种滥用——你应该使用类型自省(instanceof)和强类型。如果除了反思之外还有其他方法可以做某事,那就应该这样做。反射会导致严重的心痛,因为您失去了使用静态类型语言的所有优势。如果您需要它,则需要它,但是即使那样,我也会考虑使用诸如 Spring 之类的预打包解决方案或完全封装必要反射的东西-IE:让其他人头疼。
@bigtunacan 你从哪里得到这些信息的?我看到 Oracle 官方 Java 文档中使用的术语“反射”不仅描述了在运行时进行更改的能力,还描述了查看对象类型的能力。更不用说大多数所谓的“类型自省”相关类(例如:MethodConstructorModifierFieldMember,基本上显然除了 Class 之外的所有类)都在 {7 } 包裹。也许“反射”这个概念全面包括“类型自省”和运行时修改?
S
Sheharyar

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

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

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

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


所以换句话说,你可以用它的限定名创建一个实例,编译器不会抱怨它(因为你只使用一个字符串作为类名)。然后,在运行时,如果该类不存在,则会出现异常。在这种情况下,您有点绕过编译器。你能给我一些具体的用例吗?我只是无法想象我什么时候会选择它。
@FernandoGabrieli 虽然使用反射很容易创建运行时错误,但也完全可以使用反射而不冒运行时异常的风险。正如我的回答所暗示的,反射的一个常见用途是库或框架,它们在编译时明确无法知道应用程序的结构,因为它们是与应用程序分开编译的。任何使用“约定代码”的库都可能使用反射,但不一定使用魔术字符串。
C++ 确实具有运行时类型信息。 RTTI
b
bwegs

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

Callcount 应该设置为什么?
运行此程序时,线程“AWT-EventQueue-0”java.lang.StackOverflowError 出现异常。
@Tom callCount 应设置为零。它的值用于确定每行输出之前应该有多少个制表符:每次转储需要转储“子对象”时,输出将打印为嵌套在父对象中。当包裹在另一个中时,该方法被证明是有用的。考虑 printDump(Object obj){ System.out.println(dump(obj, 0)); }
由于未经检查的递归,可能会在循环引用的情况下创建 java.lang.StackOverflowError:buffer.append(dump(value, callCount))
你能把你的代码专门发布到公共领域吗?
G
Gary Sheppard

反射的用途

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

可扩展性功能

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

反射的缺点

反射很强大,但不应该乱用。如果可以在不使用反射的情况下执行操作,那么最好避免使用它。通过反射访问代码时应牢记以下问题。

性能开销

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

安全限制

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

内部暴露

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

来源:The Reflection API


t
toolkit

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

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

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

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


P
Pang

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

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

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


N
Nikhil Shekhar

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

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


V
VeKe

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

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

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

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

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

Exactly how all this works is explained here

编辑:将近 1 年后,我正在编辑这个答案,因为在阅读反射时,我对反射有了更多的使用。

Spring 使用 bean 配置,例如:

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

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

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

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

I
Ihor Patsian

例子:

以一个远程应用程序为例,它为您的应用程序提供一个您使用其 API Methods 获得的对象。现在根据您可能需要执行某种计算的对象。

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

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


我需要类似的东西..一个例子会对我有很大帮助,因为我是反射概念的新手..
我很困惑:你不能在运行时使用 instanceof 来确定对象类型吗?
I
Ihor Patsian

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

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

}

r
roottraveller

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

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

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

反射可用于获取有关以下内容的信息 -

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

反射 API 主要用于:

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

https://i.stack.imgur.com/zEXW5.png

使用反射的优点:

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

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

缺点:

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

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

参考:Java Reflection javarevisited.blogspot.in


我会补充缺点“It breaks refactoring”。对我来说,这是尽可能避免反思的主要原因。
所以它允许我们(例如)检查我们拥有的类(我们是否有它们的实例),对吗?我的意思是,获取它们的方法或构造函数并使用它们来创建新实例/调用它们。如果行为已经存在但使用不同的代码,为什么我们要说“改变程序行为”?为什么叫“反射”?谢谢
D
DeadChex

据我了解:

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

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

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


A
Aurelio

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

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

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

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


Y
Yoon5oo

反射就是让物体看到自己的样子。这个论点似乎与反思无关。其实,这就是“自我认同”的能力。

反射本身就是Java、C#等缺乏自知自知能力的语言的代名词。因为他们没有自知之明的能力,所以当我们要观察它的样子时,我们必须有另一件事来反思它的样子。优秀的动态语言如 Ruby 和 Python 可以感知自己的反射,而无需其他人的帮助。可以说,Java 的对象没有镜子是无法感知它的样子,这是反射类的对象,但 Python 中的对象可以在没有镜子的情况下感知它。这就是为什么我们需要在 Java 中进行反射。


type()、isinstance()、callable()、dir() 和 getattr()。 ....这些是pythonic反射调用
c
catch23

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

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

C
Community

来自 java 文档 page

java.lang.reflect 包提供了类和接口,用于获取关于类和对象的反射信息。反射允许以编程方式访问有关已加载类的字段、方法和构造函数的信息,并允许在安全限制内使用反射字段、方法和构造函数对其底层对应物进行操作。

如果必要的 ReflectPermission 可用,AccessibleObject 允许禁止访问检查。

此包中的类以及 java.lang.Class 可容纳调试器、解释器、对象检查器、类浏览器等应用程序,以及需要访问目标对象的公共成员(基于它的运行时类)或给定类声明的成员

它包括以下功能。

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

查看此 documentation 链接,了解 Class 类公开的方法。

来自此 article(由 Sosnoski Software Solutions, Inc 总裁 Dennis Sosnoski 撰写)和此 article(安全探索 pdf):

与使用反射相比,我可以看到相当多的缺点

反射用户:

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

反射的缺点:

当用于字段和方法访问时,反射比直接代码慢得多。它可以掩盖代码中实际发生的事情 它绕过源代码会产生维护问题 反射代码也比相应的直接代码更复杂 它允许违反关键的 Java 安全约束,例如数据访问保护和类型安全

一般滥用:

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

看看这个关于滥用反射功能的 SE 问题:

How do I read a private field in Java?

概括:

在系统代码中不安全地使用其功能也很容易导致 Java 安全模型受到损害。因此,请谨慎使用此功能


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

顾名思义,它反映了它所拥有的例如类方法等,除了提供在运行时动态调用创建实例的方法的功能。

许多框架和应用程序都使用它来调用服务,而无需真正了解代码。


Y
Yoon5oo

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


R
Rohil_PHPBeginner

Reflection 有许多用途。我更熟悉的是能够动态创建代码。

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


如果您只给出一个从 SQL 结果或 XML 文件等生成的代码的不寻常示例,这个答案会好得多。
没问题。我在 Windows 应用程序中使用了反射,该应用程序根据从数据库中获取的 XML 动态生成接口。
所以基本上,我创建了一个向用户显示报告的类。此报告具有诸如日期(从到)ID 或其他任何参数之类的参数。此信息存储在 xml 中。所以首先我们有一个报告选择。根据选择的报告,表单获取 xml。检索到 xml 后,它使用反射来创建一个类,其中包含基于反射类型的字段。更改为不同的报告后,将彻底清除石板并根据 xml 生成新字段。所以它本质上是一种基于反射的动态形式。我也以其他方式使用过,但这应该足够了希望有帮助
B
BSeitkazin

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

或者工作 Lombok Project。它只是在编译时注入代码,导致代码被插入到您的域类中。 (我认为 getter 和 setter 都可以)

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

从 Java 7 开始,我们有了 MethodHandles,它作为 Reflection API 工作。在项目中,要使用记录器,我们只需复制粘贴以下代码:

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

因为在这种情况下很难出现拼写错误。


c
cprn

我发现最好通过示例来解释,但似乎没有一个答案能做到这一点......

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

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


B
Bhushan

我正在使用反射基于类名(String中的类名)创建一个对象并调用该类的方法

Object obj = Class.forName(config.getClassPath())
                    .getDeclaredConstructor()
                    .newInstance();
Method method = obj.getClass().getMethod("getCustomer", SearchObject.class, ObjectConfig.class,
                HttpServletRequest.class);
method.invoke(obj, searchObject, config, request);

但一个主要问题是,如果你在那个类上自动装配了一些东西,它将重新初始化为 null


n
nitin angadi

重要的

从 Java 9 开始,您不能再使用反射,除非 package-info.java 将模块打开以进行反射访问。

默认情况下,模块中的所有包都拒绝“反射”访问。

请参阅Understanding Java 9 Modules


这是完全错误的。您仍然可以使用反射。如果包对您开放,您就无法使东西可访问 (ref.setAccessible(true);)。