jvm如何实现隐藏_反映一个隐藏的jvm超级大国

jvm如何实现隐藏

告诉我更多有关反射的信息! (Tell me more about reflection!)

Reflection is quite a powerful tool provided by the JVM. Most of the time you don’t need it, but sometimes there are problems where it comes quite handy. For me, it is always when I was confronted with the task of writing a system with plugin support. Okay, so why is reflection useful?

反射是JVM提供的功能强大的工具。 大多数情况下,您不需要它,但有时会遇到一些问题,因此非常方便。 对我来说,总是要面对编写带有插件支持的系统的任务。 好的,为什么反射有用?

Reflection lets you introspect the structure of your code at runtime. It allows developers to retrieve useful information about classes, like methods, fields, or constructors. Further, it’s also possible to instantiate new objects of this class and invoke methods of such an instantiated object. This is done by asking a class for a certain method by passing in the name of the method as a string. The problem with it: There are no compiler errors, if there’s an error it happens at runtime. I know, it sounds quite abstract at the beginning.

通过反射,您可以在运行时内省代码的结构。 它允许开发人员检索有关类的有用信息,例如方法,字段或构造函数。 此外,还可以实例化此类的新对象并调用此类实例化的方法。 这是通过将类的名称作为字符串传入来要求类提供某种方法来完成的。 问题是:没有编译器错误,如果有错误,它将在运行时发生。 我知道,一开始听起来很抽象。

When it comes to using reflection, I stick to this:

在使用反射时,我坚持:

Do not use Reflection for code you don’t own.

不要对您不拥有的代码使用反射。

There is just too much that can go wrong when you work with code that you don’t own. Internals may change without noticing or there’s a simple typo that crashes the application. And to be honest, you should never come close to the need to use reflection for any third-party code. If you ever encounter the need to do so, either make a PR to the repository if it’s open-source or search for a better alternative for your needs.

当您使用自己不拥有的代码时,可能会出错。 内部结构可能会发生变化,而不会引起注意,或者有一个简单的输入错误使应用程序崩溃。 老实说,您永远都不应接近对任何第三方代码使用反射的需求。 如果您有需要,可以对存储库进行PR(如果它是开源的),或者为您的需求寻找更好的选择。

离题:Kotlin的反思 (Digression: Reflection in Kotlin)

Reflection in Kotlin is separately shipped from the standard library and is not available out of the box. Check out more information about reflection in Kotlin here https://kotlinlang.org/docs/reference/reflection.html.

标准库中的Reflection in Kotlin是单独提供的,无法立即使用。 在https://kotlinlang.org/docs/reference/reflection.html上查看有关Kotlin中反射的更多信息。

Well, so far the theory, let’s look at some code to get a better understanding.

好了,到目前为止,理论上,让我们看一些代码以获得更好的理解。

示例1:实例化未知依赖项 (Example 1: Instantiation of unknown dependencies)

Using reflection to instantiate dependencies is a convenient way when you don’t actually know where your dependencies are located. Sounds abstract, doesn’t it? Take this simple implementation of a plugin system as an example.

当您实际上不知道依赖项位于何处时,使用反射实例化依赖项是一种方便的方法。 听起来很抽象,不是吗? 以插件系统的这种简单实现为例。

fun provideFilter(): List<Filter> {
        return reflections.getSubTypesOf(Filter::class.java)
                .map { filterClass ->
                    filterClass.newInstance()
                }
                .sortedBy { it.name }
    }

Reflection offers a way to grab all subtypes of a given interface (in this case Filter) that are registered in your classpath and instantiates them for you. You don’t have to explicitly name them when wiring together your dependencies. It will automatically add all the different subtypes to your program. In this case, all implementations must have a parameterless constructor, otherwise, filterClass.newInstance() will fail at runtime. (Which is one of the huge drawbacks of reflection, thus use it carefully!)

反射提供了一种获取给定接口的所有子类型(在本例中为Filter )的方法,该子类型已在您的类路径中注册并为您实例化。 将依赖项连接在一起时,无需显式命名它们。 它将自动将所有不同的子类型添加到您的程序。 在这种情况下,所有实现都必须具有无参数的构造函数,否则filterClass.newInstance()将在运行时失败。 (这是反射的巨大缺点之一,因此请谨慎使用!)

Note: The used object reflections is of type org.reflections.Reflections which comes from a quite neat library (https://github.com/ronmamo/reflections). This makes working with reflection so much easier.

注意:使用的对象反射类型为org.reflections.Reflections ,它来自一个非常简洁的librar y( https://github.com/ronmamo/reflections )。 这使反射工作变得非常容易。

Not convinced yet? Okay, let’s take a look at a more complex problem.

还没说服? 好吧,让我们看一个更复杂的问题。

示例2:将通用使用者连接到生产者实例 (Example 2: Connect a generic consumer to a producer instance)

Let’s say there is a data producer and a data consumer in the system. Both are connected with a pipe that transforms the data from the producer into a format that the consumer can consume.

假设系统中有一个数据生产者和一个数据使用者。 两者都通过管道连接,该管道将生产者的数据转换为消费者可以使用的格式。

In this example, the producer periodically emits data of the type int, while the consumer can only consume double values. The pipe will take care of the data transformation from int to double.

在此示例中,生产者定期发出int类型的数据,而消费者只能消耗double值。 管道将处理从intdouble的数据转换。

The Producer object holds an instance that refers to the class being instantiated while the field, which internally refers to an instance of PublishSubject<*> (from the RxJava library). The Consumer also holds an instance that refers to the consumer class being instantiated, a reference to the method that receives the data from the producer and the pipe, that is responsible for the data mapping. The method must have exactly one parameter which is of the O type of the pipe (otherwise it’ll fail at runtime).

Producer对象包含一个实例 ,该实例引用要实例化的类,而字段则内部引用PublishSubject <*>的实例(来自RxJava库)。 消费者还拥有一个实例,该实例引用要实例化的消费者类,该实例引用从生产者和管道接收数据的方法,该方法负责数据映射。 该方法必须恰好具有一个管道的O类型的参数(否则它将在运行时失败)。

Image for post
The producer pumps data via the pipe to the consumer.
生产者通过管道将数据泵送到消费者。

Well, how does it look in code now?

好吧,它现在在代码中看起来如何?

class Consumer(
      val instance: Any,   
      val method: Method,
      val pipe: EmgComponentPipe<Any, Any>
    )
    class Producer(
      val instance: Any, 
      val field: Field
    )
    ...


    fun connect(producer: Producer, consumer: Consumer) {


        (producer.field.get(producer.instance) as PublishSubject<*>)
            .subscribe { data ->
                val transformedData = consumer.pipe.pipe(data)
                consumer.method.invoke(consumer.instance, transformedData)
            }
    }

The connect method takes a producer and a consumer and connects the data stream between both. Let’s start with line 14. producer.field.get(producer.instance) accesses the field value of the instance. In normal code, one would write instance.field. However, here we have the field and want the field value of that particular instance. The cast to PublishSubject<*> is obligatory because we are assuming that the field is only of this type. This is also just an assumption. This code would crash at runtime if the field is not of type PublishSubject<*>. Line 16 just takes the pipe from the consumer and transforms the emitted data into a suitable format. No magic there. Line 17 invokes the method consumer.method on the consumer.instance object, passing in transformedData as the one and only method argument.

connect方法使用生产者和使用者,并在两者之间连接数据流。 让我们从第14行开始。producer.field.get(producer.instance)访问实例的字段值。 在普通代码中,将编写instance.field 。 但是,这里我们有一个字段,并且想要该特定实例的字段值。 强制转换为PublishSubject <*>是因为我们假设该字段仅是此类型。 这也只是一个假设。 如果该字段不是PublishSubject <*>类型,则此代码将在运行时崩溃。 第16行只是从使用者那里获取管道,然后将发出的数据转换为合适的格式。 那里没有魔术。 线17调用consumer.instance对象上的方法consumer.method,transformedData传递作为唯一方法参数。

This code connects a field from one object, that can emit data, to the method of another object, that can process the data while transforming the data if needed. Pretty cool, no?

此代码将一个对象(可以发出数据)的字段连接到另一个对象的方法,该对象可以在转换数据时处理数据。 很酷,不是吗?

These short examples should make two things clear:

这些简短的例子应该使两件事很清楚:

  1. Developers can do pretty awesome things with reflection.

    开发人员可以通过反射来做一些很棒的事情。
  2. There is so much that can go wrong with it that it should be used with caution. Actually, it should be avoided if there is another way of doing the very same task.

    它有太多可能出错的地方,应谨慎使用。 实际上,如果还有另一种方法可以完成相同的任务,则应避免这种情况。

If you want to dig deeper into reflection, here’s the link to the Github repository of my master thesis. It contains a lot of reflection code. Just explore it by yourself. https://github.com/shockbytes/EmgFramework

如果您想更深入地思考问题,请访问我的硕士论文的Github存储库。 它包含很多反射代码。 只是自己探索。 https://github.com/shockbytes/EmgFramework

翻译自: https://medium.com/@mescht93/reflection-a-hidden-jvm-superpower-54a5a70fef0d

jvm如何实现隐藏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值