Bot*_*000 17
无法抗拒和测试它,看起来几乎没有开销.
参与者是:
Interface IFoo defining a method
class Foo: IFoo implements IFoo
class Bar implements the same method as Foo, but no interface involved
Run Code Online (Sandbox Code Playgroud)
所以我定义了
Foo realfoo = new Foo();
IFoo ifoo = new Foo();
Bar bar = new Bar();
Run Code Online (Sandbox Code Playgroud)
并调用该方法,该方法执行20个字符串连接,每个变量10,000,000次.
realfoo: 723 Milliseconds
ifoo: 732 Milliseconds
bar: 728 Milliseconds
Run Code Online (Sandbox Code Playgroud)
如果该方法什么都不做,那么实际的调用会更加突出.
realfoo: 48 Milliseconds
ifoo: 62 Milliseconds
bar: 49 Milliseconds
Run Code Online (Sandbox Code Playgroud)
Nei*_*fey 12
从Java的角度来看,至少在Hotspot的最新版本中,答案通常很少或没有开销.
例如,假设您有一个如下方法:
public void doSomethingWith(CharSequence cs) {
char ch = cs.charAt(0);
...
}
Run Code Online (Sandbox Code Playgroud)
CharSequence当然是一个界面.所以你可能会期望这个方法需要做额外的工作,检查什么对象类型,找到方法,以及最后搜索界面等等 - 基本上你可以想象的所有恐怖故事......
但实际上,VM可能比这更聪明.如果它确实在实践中你总是传递特定类型的对象,那么它不仅可以跳过对象类型检查,而且甚至可以内联该方法.例如,如果你调用一个方法,如一系列字符串的循环以上,热点实际上可以内联调用的charAt(),以便获得字符字面变成换句话说,一对夫妇MOV instructions--的,一对接口的方法调用甚至可以变成甚至根本没有方法调用.(PS此信息基于1.6更新12的调试版本的汇编输出.)
由于在调用方法或访问属性时执行了额外的间接,接口确实会产生开销.许多用于实现多态的系统(包括接口的实现)通常使用基于运行时类型映射函数调用的虚方法表.
理论上,编译器可以将虚函数调用优化为普通函数调用或内联代码,前提是编译器能够证明正在进行调用的对象的历史记录.
在绝大多数情况下,使用虚函数调用的好处远远超过了缺点.
我不关心微观优化,只是想知道这需要更深入的细节.
有开销,但它是微优化级别开销.例如,一个接口可以在IL切换中从呼叫到callvirt进行多次调用,但这非常小.
是的,接口会产生开销。事实上,在逻辑和处理器之间添加的每一层都会增加开销。显然,您应该在汇编中编写所有内容,因为这是唯一不会产生开销的事情。GUI 也会产生开销,所以不要使用它们。
我是在开玩笑,但重点是你必须在清晰、可理解、可维护的代码和性能之间找到自己的平衡。对于 99.999%(当然是重复)的应用程序,只要您注意避免不必要地重复执行任何更昂贵的方法,您就永远不会达到需要使某些内容变得更难以维护的地步只是为了让它跑得更快。