有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

传递接口和重新加载类之间的java性能差异

有一种观点认为使用接口比使用类更好。我当然同意:一个接受ArrayList而不是List的库方法将是一个废物

还有一个共识是,性能总是一样的。在这里,我的benchmark请求不同意见。 results 接口和抽象类都有1到4个实现。当使用两个以上的实现时,性能开始出现差异。我正在寻找这种行为的解释(以及错误共识的起源)


共 (1) 个答案

  1. # 1 楼答案

    There's a consensus that using interfaces is better than using classes.

    这太简单了。接口和抽象类都有各自的优势

    您链接到的答案建议将变量声明为java。util。列表,而不是java。util。尽可能地列出ArrayList。正确的做法是,使用List可以让您以后更灵活地选择不同的实现类,因此,当您不需要特定于ArrayList的方法(例如.trimToCapacity())时,这是一件好事。然而,这个建议与一般的接口或类无关,如果java。util。List是一个抽象类

    There's also a consensus that the performance is always the same.

    流行的建议是,人们不应该担心类和接口之间的性能差异,而应该基于良好的编程原则在它们之间进行选择。这是一个很好的建议,可以防止程序员担心不重要的性能差异;然而,有时会被误解为暗示存在差异,这是不正确的。这里有一个小小的区别:上课更快

    通过类调用方法时,类中固定偏移量处有一个vtable,指向所需方法实现的指针位于该表中的已知偏移量处,因此跳转到目标非常简单。然而,虽然一个类只能扩展一个超类,但一个类可以实现任意数量的接口,因此通过接口的方法调用更加复杂。对于接口调用,它必须首先查找类的接口列表以找到所需的接口,然后才能在该接口的表中查找方法实现

    When more than two implementations get used, the performance starts to diverge.

    无论使用的是类还是接口,多态调用都会导致CPU上的管道刷新,因为CPU无法提前看到跳转的目标,而且成本很高。当调用站点在运行时被认为是低聚的(oligo意思是“很少”),性能会急剧提高,因为一个好的JVM会专门处理这些情况。对于单态的情况,JVM可以直接跳到单目标方法,甚至可以将其内联。对于二态的情况,它实现o.f();,好像是通过(无效语法):if (o.getClass() == A.class) A::f(o) else B::f(o);

    事实上,我不确定为什么在你的基准测试中,二态情况似乎和单态情况一样快——CPU的分支预测器在随机数据上不应该有一半的时间出错吗?也许还有其他微妙之处在起作用

    另见: