什么是反射以及为什么它有用?

发布于 2024-07-04 19:05:28 字数 61 浏览 6 评论 0原文

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

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

What is reflection, and why is it useful?

I'm particularly interested in Java, but I assume the principles are the same in any language.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(24

对风讲故事 2024-07-11 19:05:28

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

或者可以使用Lombok Project。 它只是在编译时注入代码,导致代码被插入到您的域类中。 (我认为这对于 getter 和 setter 来说是可以的)

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

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

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

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

I want to answer this question by example. First of all Hibernate project uses Reflection API to generate CRUD statements to bridge the chasm between the running application and the persistence store. When things change in the domain, the Hibernate has to know about them to persist them to the data store and vice versa.

Alternatively works Lombok Project. It just injects code at compile time, result in code being inserted into your domain classes. (I think it is OK for getters and setters)

Hibernate chose reflection because it has minimal impact on the build process for an application.

And from Java 7 we have MethodHandles, which works as Reflection API. In projects, to work with loggers we just copy-paste the next code:

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

Because it is hard to make typo-error in this case.

北座城市 2024-07-11 19:05:28

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

IE:动态类、函数、构造函数 - 基于任何数据
(xml/数组/sql 结果/硬编码/等..)

Reflection has many uses. The one I am more familiar with, is to be able to create code on the fly.

IE: dynamic classes, functions, constructors - based on any data
(xml/array/sql results/hardcoded/etc..)

风情万种。 2024-07-11 19:05:28

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

Reflection gives you the ability to write more generic code. It allows you to create an object at runtime and call its method at runtime. Hence the program can be made highly parameterized. It also allows introspecting the object and class to detect its variables and method exposed to the outer world.

情仇皆在手 2024-07-11 19:05:28

正如名称本身所暗示的那样,它除了提供在运行时动态调用方法创建实例的功能之外,还反映了它所拥有的内容,例如类方法等。

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

As name itself suggest it reflects what it holds for example class method,etc apart from providing feature to invoke method creating instance dynamically at runtime.

It is used by many frameworks and application under the wood to invoke services without actually knowing the code.

や莫失莫忘 2024-07-11 19:05:28

来自java文档页面

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

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

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

它包括以下功能。

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

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

摘自这篇文章(作者:Dennis Sosnoski,Sosnoski Software Solutions, Inc. 总裁)这篇文章(security-explorations pdf):

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

反射的用户:

  1. 它提供了动态链接程序组件的非常通用的方法
  2. 它对于创建与非常通用的对象一起使用的库非常有用 反射的缺点

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

一般滥用:

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

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

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

总结:

在系统代码中对其功能的不安全使用也很容易导致Java安全模式的泄露l。 所以请谨慎使用此功能

From java documentation page

java.lang.reflect package provides classes and interfaces for obtaining reflective information about classes and objects. Reflection allows programmatic access to information about the fields, methods and constructors of loaded classes, and the use of reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

AccessibleObject allows suppression of access checks if the necessary ReflectPermission is available.

Classes in this package, along with java.lang.Class accommodate applications such as debuggers, interpreters, object inspectors, class browsers, and services such as Object Serialization and JavaBeans that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class

It includes following functionality.

  1. Obtaining Class objects,
  2. Examining properties of a class (fields, methods, constructors),
  3. Setting and getting field values,
  4. Invoking methods,
  5. Creating new instances of objects.

Have a look at this documentation link for the methods exposed by Class class.

From this article (by Dennis Sosnoski, President, Sosnoski Software Solutions, Inc) and this article (security-explorations pdf):

I can see considerable drawbacks than uses of using Reflection

User of Reflection:

  1. It provides very versatile way of dynamically linking program components
  2. It is useful for creating libraries that work with objects in very general ways

Drawbacks of Reflection:

  1. Reflection is much slower than direct code when used for field and method access.
  2. It can obscure what's actually going on inside your code
  3. It bypasses the source code can create maintenance problems
  4. Reflection code is also more complex than the corresponding direct code
  5. It allows violation of key Java security constraints such
    as data access protection and type safety

General abuses:

  1. Loading of restricted classes,
  2. Obtaining references to constructors, methods or fields of a restricted class,
  3. Creation of new object instances, methods invocation, getting or setting field values of a restricted class.

Have a look at this SE question regarding abuse of reflection feature:

How do I read a private field in Java?

Summary:

Insecure use of its functions conducted from within a system code can also easily lead to the compromise of a Java security model. So use this feature sparingly

云巢 2024-07-11 19:05:28

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

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

Reflection is to let object to see their appearance. This argument seems nothing to do with reflection. In fact, this is the "self-identify" ability.

Reflection itself is a word for such languages that lack the capability of self-knowledge and self-sensing as Java and C#. Because they do not have the capability of self-knowledge, when we want to observe how it looks like, we must have another thing to reflect on how it looks like. Excellent dynamic languages such as Ruby and Python can perceive the reflection of their own without the help of other individuals. We can say that the object of Java cannot perceive how it looks like without a mirror, which is an object of the reflection class, but an object in Python can perceive it without a mirror. So that's why we need reflection in Java.

明媚如初 2024-07-11 19:05:28

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

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

I just want to add some points to all that was listed.

With Reflection API you can write a universal toString() method for any object.

It could be useful for debugging.

Here is some example:

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;
   }    
}
森末i 2024-07-11 19:05:28

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

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

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

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

Reflection is a set of functions which allows you to access the runtime information of your program and modify it behavior (with some limitations).

It's useful because it allows you to change the runtime behavior depending on the meta information of your program, that is, you can check the return type of a function and change the way you handle the situation.

In C# for example you can load an assembly (a .dll) in runtime an examine it, navigating through the classes and taking actions according to what you found. It also let you create an instance of a class on runtime, invoke its method, etc.

Where can it be useful? Is not useful every time but for concrete situations. For example you can use it to get the name of the class for logging purposes, to dynamically create handlers for events according to what's specified on a configuration file and so on...

ゝ杯具 2024-07-11 19:05:28

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

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

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

Reflection 可用于获取有关 -

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

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

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

Reflection API主要用于:

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

使用反射的优点:

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

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

缺点:

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

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

参考: Java 反射 javarevisited.blogspot.in

Reflection is an API which is used to examine or modify the behaviour of methods, classes, interfaces at runtime.

  1. The required classes for reflection are provided under java.lang.reflect package.
  2. Reflection gives us information about the class to which an object belongs and also the methods of that class which can be executed by using the object.
  3. Through reflection we can invoke methods at runtime irrespective of the access specifier used with them.

The java.lang and java.lang.reflect packages provide classes for java reflection.

Reflection can be used to get information about –

  1. Class The getClass() method is used to get the name of the class to which an object belongs.

  2. Constructors The getConstructors() method is used to get the public constructors of the class to which an object belongs.

  3. Methods The getMethods() method is used to get the public methods of the class to which an objects belongs.

The Reflection API is mainly used in:

IDE (Integrated Development Environment) e.g. Eclipse, MyEclipse, NetBeans etc.
Debugger and Test Tools etc.

Advantages of Using Reflection:

Extensibility Features: An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.

Debugging and testing tools: Debuggers use the property of reflection to examine private members on classes.

Drawbacks:

Performance Overhead: Reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

Exposure of Internals: Reflective code breaks abstractions and therefore may change behaviour with upgrades of the platform.

Ref: Java Reflection javarevisited.blogspot.in

可遇━不可求 2024-07-11 19:05:28

根据我的理解:

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

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

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

As per my understanding:

Reflection allows programmer to access entities in program dynamically. i.e. while coding an application if programmer is unaware about a class or its methods, he can make use of such class dynamically (at run time) by using reflection.

It is frequently used in scenarios where a class name changes frequently. If such a situation arises, then it is complicated for the programmer to rewrite the application and change the name of the class again and again.

Instead, by using reflection, there is need to worry about a possibly changing class name.

短暂陪伴 2024-07-11 19:05:28

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

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

}

Simple example for reflection.
In a chess game, you do not know what will be moved by the user at run time. reflection can be used to call methods which are already implemented at run time:

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

}
む无字情书 2024-07-11 19:05:28

示例:

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

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

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

Example:

Take for example a remote application which gives your application an object which you obtain using their API Methods . Now based on the object you might need to perform some sort of computation .

The provider guarantees that object can be of 3 types and we need to perform computation based on what type of object .

So we might implement in 3 classes each containing a different logic .Obviously the object information is available in runtime so you cannot statically code to perform computation hence reflection is used to instantiate the object of the class that you require to perform the computation based on the object received from the provider .

别在捏我脸啦 2024-07-11 19:05:28

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

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

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

Not every language supports reflection, but the principles are usually the same in languages that support it.

Reflection is the ability to "reflect" on the structure of your program. Or more concrete. To look at the objects and classes you have and programmatically get back information on the methods, fields, and interfaces they implement. You can also look at things like annotations.

It's useful in a lot of situations. Everywhere you want to be able to dynamically plug in classes into your code. Lots of object relational mappers use reflection to be able to instantiate objects from databases without knowing in advance what objects they're going to use. Plug-in architectures is another place where reflection is useful. Being able to dynamically load code and determine if there are types there that implement the right interface to use as a plugin is important in those situations.

美人迟暮 2024-07-11 19:05:28

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

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

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

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

Reflection is a key mechanism to allow an application or framework to work with code that might not have even been written yet!

Take for example your typical web.xml file. This will contain a list of servlet elements, which contain nested servlet-class elements. The servlet container will process the web.xml file, and create new a new instance of each servlet class through reflection.

Another example would be the Java API for XML Parsing (JAXP). Where an XML parser provider is 'plugged-in' via well-known system properties, which are used to construct new instances through reflection.

And finally, the most comprehensive example is Spring which uses reflection to create its beans, and for its heavy use of proxies

软的没边 2024-07-11 19:05:28

反射的使用

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

可扩展性功能

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

反射的缺点

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

  • 性能开销

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

  • 安全限制

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

  • 暴露内部

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

来源:反射 API

Uses of Reflection

Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.

Extensibility Features

An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.
Class Browsers and Visual Development Environments
A class browser needs to be able to enumerate the members of classes. Visual development environments can benefit from making use of type information available in reflection to aid the developer in writing correct code.
Debuggers and Test Tools
Debuggers need to be able to examine private members in classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to ensure a high level of code coverage in a test suite.

Drawbacks of Reflection

Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing code via reflection.

  • Performance Overhead

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations cannot be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts and should be avoided in sections of code which are called frequently in performance-sensitive applications.

  • Security Restrictions

Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet.

  • Exposure of Internals

Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.

source: The Reflection API

紫瑟鸿黎 2024-07-11 19:05:28

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

One of my favorite uses of reflection is the below Java dump method. It takes any object as a parameter and uses the Java reflection API to print out every field name and value.

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();
}
太阳男子 2024-07-11 19:05:28

Java Reflection 非常强大并且非常有用。
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上下文处理这个
时 豆> 元素,它将使用 Class.forName(String) 和参数“com.example.Foo”来实例化该类。

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

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

Java Reflection is quite powerful and can be very useful.
Java Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing the names of the classes, methods etc. at compile time.
It is also possible to instantiate new objects, invoke methods and get/set field values using reflection.

A quick Java Reflection example to show you what using reflection looks like:

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

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

This example obtains the Class object from the class called MyObject. Using the class object the example gets a list of the methods in that class, iterates the methods and print out their names.

Exactly how all this works is explained here

Edit: After almost 1 year I am editing this answer as while reading about reflection I got few more uses of Reflection.

  • Spring uses bean configuration such as:

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

When the Spring context processes this < bean > element, it will use Class.forName(String) with the argument "com.example.Foo" to instantiate that Class.

It will then again use reflection to get the appropriate setter for the < property > element and set its value to the specified value.

  • Junit uses Reflection especially for testing Private/Protected methods.

For Private methods,

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

For private fields,

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
书信已泛黄 2024-07-11 19:05:28

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

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。 如果该方法不是静态的,那么在调用时您需要提供一个有效的 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,但如果过度使用,它可能会减慢应用程序的速度,因为它会在运行时解析所有类型。

Reflection allows instantiation of new objects, invocation of methods, and get/set operations on class variables dynamically at run time without having prior knowledge of its implementation.

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

In above example the null parameter is the object you want to invoke the method on. If the method is static you supply null. If the method is not static, then while invoking you need to supply a valid MyObject instance instead of null.

Reflection also allows you to access private member/methods of a class:

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);
  • For inspection of classes (also know as introspection) you don't need to import the reflection package (java.lang.reflect). Class metadata can be accessed through java.lang.Class.

Reflection is a very powerful API but it may slow down the application if used in excess, as it resolves all the types at runtime.

苍白女子 2024-07-11 19:05:28

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

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

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

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

Reflection is a language's ability to inspect and dynamically call classes, methods, attributes, etc. at runtime.

For example, all objects in Java have the method getClass(), which lets you determine the object's class even if you don't know it at compile time (e.g. if you declared it as an Object) - this might seem trivial, but such reflection is not possible in less dynamic languages such as C++. More advanced uses lets you list and call methods, constructors, etc.

Reflection is important since it lets you write programs that do not have to "know" everything at compile time, making them more dynamic, since they can be tied together at runtime. The code can be written against known interfaces, but the actual classes to be used can be instantiated using reflection from configuration files.

Lots of modern frameworks use reflection extensively for this very reason. Most other modern languages use reflection as well, and in scripting languages (such as Python) they are even more tightly integrated, since it feels more natural within the general programming model of those languages.

树深时见影 2024-07-11 19:05:28

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

例如,假设您有一个 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++

The name reflection is used to describe code which is able to inspect other code in the same system (or itself).

For example, say you have an object of an unknown type in Java, and you would like to call a 'doSomething' method on it if one exists. Java's static typing system isn't really designed to support this unless the object conforms to a known interface, but using reflection, your code can look at the object and find out if it has a method called 'doSomething' and then call it if you want to.

So, to give you a code example of this in Java (imagine the object in question is foo) :

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

One very common use case in Java is the usage with annotations. JUnit 4, for example, will use reflection to look through your classes for methods tagged with the @Test annotation, and will then call them when running the unit test.

There are some good reflection examples to get you started at http://docs.oracle.com/javase/tutorial/reflect/index.html

And finally, yes, the concepts are pretty much similar in other statically typed languages which support reflection (like C#). In dynamically typed languages, the use case described above is less necessary (since the compiler will allow any method to be called on any object, failing at runtime if it does not exist), but the second case of looking for methods which are marked or work in a certain way is still common.

Update from a comment:

The ability to inspect the code in the system and see object types is
not reflection, but rather Type Introspection. Reflection is then the
ability to make modifications at runtime by making use of
introspection. The distinction is necessary here as some languages
support introspection, but do not support reflection. One such example
is C++

为你拒绝所有暧昧 2024-07-11 19:05:28

重要

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

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

请参阅了解 Java 9 模块

IMPORTANT

Starting from Java 9 you can no longer use reflection, unless the package-info.java opens the module to reflection access.

By default, "reflection" access is denied to all packages in the module.

See Understanding Java 9 Modules

夜夜流光相皎洁 2024-07-11 19:05:28

如果您想快速了解对象中的值,这里有一个有趣的实现,

        Class<?> classes = exampleObject.getClass();
        Field[] fields = classes.getDeclaredFields();
        for (Field field: fields){
            field.setAccessible(true);
            Object value;
            try {
                value = field.get(exampleObject);
            } catch (IllegalAccessException e){
                throw new RuntimeException(e);
            }
            logger.info("exampleObject: "+field.getName() + " value: "+value);
        }

不要忘记导入此 import java.lang.reflect.Field; 包。

If you want to have a sneek peek of the values in an Object, here's a fun implementation

        Class<?> classes = exampleObject.getClass();
        Field[] fields = classes.getDeclaredFields();
        for (Field field: fields){
            field.setAccessible(true);
            Object value;
            try {
                value = field.get(exampleObject);
            } catch (IllegalAccessException e){
                throw new RuntimeException(e);
            }
            logger.info("exampleObject: "+field.getName() + " value: "+value);
        }

Don't forget to import this import java.lang.reflect.Field; package.

暮凉 2024-07-11 19:05:28

我正在使用反射根据类名(字符串中的类名)创建一个对象并调用该类的方法,

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

I am using reflection to create an object based on class name(class name in String) and call the method of that class

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

But one major problem is that if you Autowired something on that class that will re-initialized to null

萌无敌 2024-07-11 19:05:28

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

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

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

As I find it best to explain by example and none of the answers seem to do that...

A practical example of using reflections would be a Java Language Server written in Java or a PHP Language Server written in PHP, etc. Language Server gives your IDE abilities like autocomplete, jump to definition, context help, hinting types and more. In order to have all tag names (words that can be autocompleted) to show all the possible matches as you type the Language Server has to inspect everything about the class including doc blocks and private members. For that it needs a reflection of said class.

A different example would be a unit-test of a private method. One way to do so is to create a reflection and change the method's scope to public in the test's set-up phase. Of course one can argue private methods shouldn't be tested directly but that's not the point.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文