【问题标题】:Java reflection run-time performanceJava 反射运行时性能
【发布时间】:2015-08-22 09:33:10
【问题描述】:

这是一个学术练习(免责声明)。

我正在构建一个应用程序,该应用程序将受益于尽可能快,因为它将与其他人竞争。

我知道与标准声明相比,使用反射声明一个类(下面的示例)将遭受巨大的损失。

Class mDefinition = Class.forName("MySpecialClassString");
Constructor mConstructor = mDefinition.getConstructor(new Class[]{MySpecialClass.class});
myClass = (MySpecialClass) mConstructor.newInstance(this);

但是,在声明 myClass 之后,如果我以标准方式使用它 myClass.myMethod() 我也会遭受性能损失,还是就像我在标准时尚?

【问题讨论】:

    标签: java performance reflection


    【解决方案1】:

    第一次实例化对象时会有性能损失。类一旦加载完毕,就和正常实例化一样,不会有进一步的性能损失。

    更进一步,如果使用反射调用方法,将会有大约十五倍的性能损失(Java 中的默认值),之后反射调用将被 JVM 重写为与静态编译调用完全相同.因此,一旦该字节码被 JVM 重新编译,即使是重复反射的方法调用也不会导致性能下降。

    有关更多信息,请参阅这两个链接:

    【讨论】:

    • 感谢非常详细的描述和额外的文档。最近几天确实证明很有用。
    【解决方案2】:

    一旦加载了类,你应该没问题。开销与检查表示类的运行时结构等有关。以标准方式调用方法应该没问题,但是如果您开始按名称或签名搜索方法,则会产生额外的开销。

    【讨论】:

    • +1 同意 - 一次性动态查找不应该花费太多。
    • @Chris 我一直在进行一些测试,您的假设是正确的。感谢您预先清除此问题。
    【解决方案3】:

    克里斯汤普森的回答是正确的。但是我对您的代码示例感到困惑。

    这将动态加载类:

    Class mDefinition = Class.forName("MySpecialClassString");
    

    这将为您的类获得一个Contructor,它将同一类的一个实例作为参数。另请注意,您在编译时使用MySpecialClass.class 访问该类:

    Constructor mConstructor = mDefinition.getConstructor(new Class[]{MySpecialClass.class});
    

    这是通过将this 传递给构造函数来实例化MySpecialClass:

    myClass = (MySpecialClass) mConstructor.newInstance(this);
    

    基于构造函数参数,这是否意味着我们处于MySpecialClass 的实例方法中?很困惑。

    编辑:这更接近我的预期:

    Class<?> mDefinition = Class.forName("MySpecialClassString");
    
    //constructor apparently takes this as argument
    Class<?> constructorArgType = this.getClass(); //could be ThisClassName.class
    
    Constructor<?> mConstructor = mDefinition.getConstructor(constructorArgType);
    
    MySpecialInterface mySpecialInstance = (MySpecialInterface)mConstructor.newInstance(this);
    

    其中MySpecialInterface 是用于与动态加载的类进行交互的接口:

    interface MySpecialInterface {
        //methods used to interface with dynamically loaded classes
    }
    

    无论如何,如果我在这里有误解或离题,请告诉我。

    【讨论】:

    • 你可能是对的,因为我现在才刚刚开始使用反射。让我快速向您简要介绍一下该系统的工作原理。我们有三个类 ClassA_interaction、ClassB_object 和 ClassC_logic... ClassA_interaction 启动几个 ClassB_object 并为它们提供位置。每个 ClassB_object 使用反射启动一个 ClassC_logic。 ClassC_logic 由this (ClassB_object) 提供,因为它们必须调用存在于 ClassB_object 上的函数。它可能很乱但有效。你会建议我采取另一种方法吗?感谢您花时间查看我的代码。
    • 我不得不说我没有亲自使用过动态类加载,这就是为什么我想得到某人的确认。但是,我的理解是,如果您直接在代码中引用一个类,甚至在编译时可以访问它,那么动态加载它是没有意义的。但是,如果您有一个静态加载的Foo,它是一个抽象类或接口,并且您的动态加载的类扩展/实现Foo,这将是有意义的。这样,在您动态加载一个类并实例化它之后,您可以将其转换为 Foo 并与它进行交互,而无需进一步反射。
    • 当然,Foo 需要以抽象/接口方法声明的形式了解您想要对这些动态加载的类执行的所有操作。
    • 动态类加载(在我的情况下)仅用于一个目的,游戏是使用具有地图名称的 txt 文件提供的。地图是预先给定的,我们可以(应该)为每张地图制定不同的策略。因此地图的名称将决定加载哪个类。
    • 这些不同的策略可以归入通用的抽象方法吗?另外,动态加载类的原因是什么 - 速度?一个在编译时可用的类仍然不会被加载,直到在运行时需要它。或者这些地图/行为直到在运行时才可用?
    猜你喜欢
    • 1970-01-01
    • 2010-09-30
    • 2011-07-13
    • 2014-07-29
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 2014-08-29
    相关资源
    最近更新 更多