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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:29:21  来源:igfitidea点击:

What is reflection and why is it useful?

javareflectionterminology

提问by Lehane

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.

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

采纳答案by Matt Sheppard

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.

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

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

因此,在 Java 中为您提供一个代码示例(假设有问题的对象是 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.

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

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

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.

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

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++

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

回答by Jorge Córdoba

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.

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

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...

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

回答by Mendelt

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 usefull in a lot of situations. Everywhere you want to be able to dynamically plug in classes into your code. Lot's 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 usefull. 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.

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

回答by Liedman

Reflectionis 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.

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

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.

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

回答by toolkit

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.

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

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.

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

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

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

回答by Ben Williams

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.

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

回答by pramod

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.

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

回答by human.js

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 .

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

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

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

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 .

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

回答by Ess Kay

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

Reflection有很多用途。我更熟悉的是能够即时创建代码。

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

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

回答by Nikhil Shekhar

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.

在上面的例子中,null 参数是你想要调用方法的对象。如果该方法是静态的,则您提供 null。如果该方法不是静态的,则在调用时需要提供有效的 MyObject 实例而不是 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.
  • 对于类的检查(也称为自省),您不需要导入反射包 ( java.lang.reflect)。类元数据可以通过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.

反射是一个非常强大的 API,但如果过度使用它可能会减慢应用程序的速度,因为它会在运行时解析所有类型。