计算机资源是RAM,拥有电源和磁盘空间。我只是好奇,即使它或多或少只是一点点的小额。
答案 0 :(得分:3)
私有函数使用的计算机资源多于或少于公共计算机资源?
没有。无论各个字段或方法上的访问修饰符如何,JVM都使用相同的资源。
但,除了资源利用率之外,还有更好的理由选择private
(或protected
);即encapsulation。另外,我强烈建议您阅读The Developer Insight Series: Part 1 - Write Dumb Code。
答案 1 :(得分:3)
使用invokevirtual
字节码op调用非静态非公共方法。此操作码要求JVM动态查找实际的方法解析:如果您有一个静态编译为AbstractList::contains
的调用,是否应该解析为ArrayList::contains
或LinkedList::contains
等?更重要的是,编译器不能只重用下次编译的结果;如果下次myList.contains(val)
被调用,它会在不同的实现上呢?因此,对于非私有方法,编译器必须至少执行一些大量的检查,大致是每次调用。
无法覆盖私有方法,并且使用invokespecial
调用它们。这个操作码用于各种类型的方法调用,你只能解析一次,然后永远不会改变:构造函数,调用超级方法等。例如,如果我在ArrayList::add
并且我调用{{1 (这不会发生,但让我们假装它),然后编译器可以确定这引用super.add(value)
,因为类的超类不能改变。
因此,非常粗略地说,AbstractList::add
调用需要解析方法然后调用它,而invokevirtual
调用不需要解析方法(在第一次调用之后 - 你必须至少解决一次!)。
对一次invokedynamic指令的符号引用的解析意味着对于任何其他invokedynamic指令,都认为相同的符号引用被解析。
对于上述所有其他指令,一次出现的指令的符号引用的分辨率意味着相同的符号引用被认为已解析为任何其他非调用动态指令。
(原文为empahsis)
好的,现在为“但你不会注意到差异”部分。 JVM针对虚拟调用进行了大量优化。它可以执行以下操作:检测特定网站是否始终专门看到invokespecial
,从而将ArrayList
调用“静态化”为实际为List::add
。要做到这一点,它需要验证传入的对象是否真的是预期的ArrayList::add
,但这非常便宜;如果某个早期方法调用已经在此方法中完成了该工作,则不需要再次进行。这称为单态调用站点:即使代码在技术上是多态的,实际上列表只有一个表单。
JVM优化单态调用站点,甚至是双态调用站点(例如,列表总是ArrayList
或ArrayList
,而不是其他任何东西。一旦它看到三种形式,就必须使用完整的多态分派,这种分配速度较慢。但话说回来,那时候你将苹果与橙子进行比较:对私人调用的非私有,多态调用,按照定义单态。比较两种单态调用(虚拟和私有)更公平,在这种情况下,如果它甚至可以检测到,你可能会发现差异是微不足道的。
我只是做a quick JMH benchmark来比较(a)直接访问字段,(b)通过公共getter访问它,以及(c)通过私有getter访问它。这三个人花了相同的时间。当然,超级微基准很难做到正确,因为JIT可以通过优化做出如此美妙的事情。然后,这就是点:JIT通过优化公共和私有方法同样快速地完成了这些奇妙的事情。
答案 2 :(得分:1)
我只是好奇,即使它或多或少只是一点点的小额。
虽然好奇是好的...如果你在编程时考虑这种事情,那么:
您可能会浪费大量时间寻找不需要的微优化,
您的代码可能无法维护,因为您牺牲了良好的设计原则,
你甚至冒险使你的代码更少有效 * ,而不是你没有优化。
* - 它可以像这样。 1)您花了很多时间调整代码,以便在测试平台上快速运行。 2)当您在生产平台上运行时,您会发现硬件为您提供了不同的性能特征。 3)升级Java安装,新JVM的JIT编译器以不同方式优化您的代码,或者通过调整实现一系列禁止的新优化。 4)当您在实际工作负载上运行代码时,您会发现作为调整基础的假设无效。