优化速度:私有变量和公共变量 - Java

5

我提出这个问题是为了讨论速度方面的问题。

在Java中,从对象获取值时,私有或公共有什么速度差别?

class MyClass {
    public int myInt = 5;
}
class MyOtherClass {
    private int myInt = 5;

    public int getMyInt() {
        return myInt;
    }
}
class MyMainClass {
    public static void main (String [] args) {
        MyClass myObject = new MyClass();
        MyOtherClass myOtherObject = new MyOtherClass();

        // which is faster?
        System.out.println(myObject.myInt);
        System.out.println(myOtherObject.getMyInt ());
    }
}

我知道我可以测试它,但如果有人已经知道了,那也无妨 :) 提前感谢!


应该测试它。而且你不应该进行微基准测试,而是尝试在一个真正执行一些有用工作的大型程序上运行它,并让它运行一分钟,因为这是优化真正起作用的维度。每次你考虑微观优化时都要这样做,直到这种能量浪费从你的思维过程中被消除。 - user395760
@delnan,我不确定您的意思是什么。如果您的意思是在大程序的上下文中,“特定”的优化可能有无法衡量的好处,那么从定义上讲,这有点正确。一个专门编写的测试,在哪种方式更好的一般适用的理解方面,还是有启示意义的,不是吗?当然,由于您不知道内存管理函数何时运行等等,您可能需要迭代很长时间。我不认为需要一个真正的能够完成实际工作的现实世界程序。 - H2ONaCl
@broiyan:如果它只对微基准测试有任何(相关的)影响,那么实际解决问题的程序不会从中受益。如果它不能加速解决实际问题,那么它就没有任何价值,不值得担心。如果它使您的微基准测试运行更快,也没有人在意。如果存在技术深度(例如由于封装不足而导致更糟糕的设计),则这种情况会变得更加严重。值得关注和实施的优化即使在执行大量其他任务的实际程序中也带来可衡量的好处(记住80-20法则!)。 - user395760
5个回答

13

公共访问和私有访问只是在编译时决定是否可以访问变量。在运行时,它们完全相同。这意味着如果你能欺骗JVM认为你有权限(通过反射,unsafe或修改字节码),那么你就可以访问。公共和私有只是编译时的信息。这并不意味着它没有存储在字节码中,因为它确实存储在其中,但只是为了在有需要时作为引用。


调用函数的麻烦压根不重要吗? - Hidde
1
@Hidde:在JIT启动后,它很容易内联该调用。即使它没有这样做,也有许多可以优化的东西,而不会使您的设计变得更糟。 - user395760
谢谢 :) 我实际上完全忘记了内联函数。 - Hidde
1
只有当方法被声明为“final”并且内联访问不会违反访问控制时,编译器才会将其内联。否则,它必须等到运行时才能执行。 - erickson
字节码验证器无法知道你是否打算将字段设置为公共或私有 - 它只保证所有访问遵循所呈现的模型。如果我更改类的字节码,使其字段公开而不是私有,则字节码验证器将愉快地允许其他类直接引用该字段。最后一句话的最后一个从句可能不是1000%准确的,但它非常接近。“非常错误”是答案的错误描述。 - corsiKa
显示剩余5条评论

9

字段上的访问修饰符对速度没有影响,但调用访问器方法有。

然而,差异不大,并且由于JIT编译器的优化,在重复调用后可能会减少。这取决于你的情况,但我没有找到一种情况,其中性能问题可以证明消除访问器是必要的。让良好的设计原则驱动您的决策。

在这种情况下有助于提高性能的一个好的设计原则是禁止继承,除非你知道它是需要的并已经采取了支持它的步骤。特别是,将类声明为final(或至少访问器方法)将提供更快的方法分派,并可能作为提示给JITC以更积极地进行内联。

保持访问器为final也允许编译器内联对访问器的调用。如果字段是私有的,则来自类内部的访问器调用可以被内联(在良好的设计中,这些远远是最常见的情况),而包访问字段可以在整个包中内联等。


对于许多好的智慧珍珠,加1分。设计原则>性能(尤其是微优化)是其中之一。将其设为final也是一个相当不错的想法,因为我认为在子类中重写直接访问方法是不明智的,这样我就没有理由不将其设为final。 - corsiKa

1
据我所知,当您调用getter或任何仅返回某个值而不做其他操作的函数时,该方法将被内联,因此在方法调用和直接访问字段之间没有任何区别。

1

你询问如何访问私有变量和公共变量,但是你的代码示例和对glowcoder提示的评论表明你实际上在询问私有字段与公共方法之间的区别(或者说,字段与方法...正如glowcoder所说,公共与私有对性能没有影响)。

许多现代编译器将优化对短方法的调用,使其等效于对它们包装的字段的访问(通过内联调用),但是可能会在给定的Java环境中执行函数调用(稍微慢一些)来调用该方法。

生成内联代码还是函数调用取决于特定的编译器。如果不知道你使用的Java编译器(可能还包括编译器选项),就无法确定。


0

从性能角度来看,如果有任何区别的话,那么这种差异微不足道。编译器几乎会以相同的方式优化此代码,一旦代码被编译,JVM将完全以相同的方式处理公共和私有变量(我甚至不认为它在后编译时知道公共和私有之间的区别)。

从实用的角度来看,很难想象出任何可能的情况,值得为了性能而打破传统的Java属性访问模式。在StackOverflow上曾经有一个类似的关于C++的问题,答案对于Java也同样适用:

是否有任何性能原因要将属性设置为protected/private?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接