2011-08-19 66 views
11

这是一个学术演习(免责声明)。Java反射运行时性能

我正在构建一个应用程序,它将尽可能快地从中获利,因为它会与其他人竞争。

我知道使用反射声明一个类(下面的例子)将遭受巨大的惩罚,而不是标准声明。

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

然而,宣告myClass如果我用它以标准方式myClass.myMethod(),我也要从性能猪吃亏的还是会是一样的,如果我宣布以标准方式后级?

回答

14

当您第一次实例化对象时会有性能损失。一旦这个类被加载,它就像它被正常实例化一样,并且不会有进一步的性能损失。更进一步,如果您使用反射调用方法,将会有约15倍的性能损失(默认为Java),之后反射调用将被JVM重写为与静态编译完全相同呼叫。因此,即使重复反映的方法调用不会导致性能下降,一旦该字节码已被JVM重新编译。

查看这两个链接,了解更多信息:

+0

thks的相当详细的说明和额外的文件。在过去的几天里证明是有用的。 – Frankie

7

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

+1

+1同意 - 应该有一个一次性的动态查找没有很大的代价。 –

+0

@Chris我一直在进行一些测试,你对你的假设是正确的。感谢您对此进行预先清理。 – Frankie

2

克里斯汤普森的答案是关键。不过,我很困惑你的代码示例。

这将动态加载类:

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 
} 

无论如何请让我知道,如果我误解或基地在这里。

+0

你可能是对的,因为我现在刚开始使用反射。让我快速介绍系统的工作原理。我们有三个类:ClassA_interaction,ClassB_object和ClassC_logic ... ClassA_interaction启动几个ClassB_objects并为它们提供位置。每个ClassB_object使用反射启动一个ClassC_logic。 ClassC_logic使用'this'(ClassB_object)提供,因为它们必须调用ClassB_object上存在的函数。 它可能是凌乱的,但工程。你会建议我采取另一种方法吗?请花些时间看看我的代码。 – Frankie

+0

我不得不说我没有亲自使用动态类加载,这就是为什么我想要某人的确认。但是,我的理解是,如果您直接在代码中引用某个类,或者甚至可以在编译时访问它,则没有必要动态加载它。然而,如果你有一个静态加载的'Foo',它可能是一个抽象类或接口,并且你的动态加载的类扩展/实现'Foo',这将是有意义的。在你动态地加载一个类并实例化它之后,你可以将它转换为'Foo'并与之交互,而无需进一步反思。 –

+0

当然,'Foo'需要用抽象/接口方法声明的形式知道你要用这​​些动态加载的类来做的所有事情。 –