与java中的私有/受保护方法相关的性能与设计[关闭]

Posted

技术标签:

【中文标题】与java中的私有/受保护方法相关的性能与设计[关闭]【英文标题】:Performance vs Design related to private/protected methods in java [closed] 【发布时间】:2012-02-29 19:20:36 【问题描述】:

我们正在与一位朋友讨论有关 java 代码设计和效率的问题。

他认为,出于性能原因以及覆盖时的类一致性保护,方法最好是私有的。

我认为最好保护方法以实现完全可定制性,并避免在用户想要更改其部分行为时立即修改和发布 API 浪费时间。

我们知道对composition over inheritance的偏好,所以这里我主要关注性能比较。

一个简单的测试(见下文)证明父类具有受保护方法的扩展类并不比父类具有私有方法的扩展类慢。它甚至有时(我不太了解性能变化)更快。

elapsed:8051733.063 microseconds for A (private)
elapsed:8036953.805 microseconds for B (protected)

您认为下面提到的测试是否足够稳健以进行比较?

public class VerifPerfProtected 
public static void main(String[] args) 
    int ncalls = 1000000000; //10^9
    ChildrenClassA a = new ChildrenClassA();
    ChildrenClassB b = new ChildrenClassB();

    long start = System.nanoTime();
    a.manyCalls(ncalls);
    long stop = System.nanoTime();
    System.out.println("elapsed:" + (stop - start)/1000.0 + " microseconds for A (private)");

    start = System.nanoTime();
    b.manyCalls(ncalls);
    stop = System.nanoTime();
    System.out.println("elapsed:" + (stop - start)/1000.0 + " microseconds for B (protected)");


public static class ParentClassA
    public void manyCalls(int n)
        for (int i = 0; i < n; i++) 
            callAmethod();
        
    
    public void callAmethod()
        aPrivateMethod();
    
    private void aPrivateMethod()
        int a=0;
        for (int i = 0; i < 5; i++) 
            a++;
        
    


public static class ParentClassB
    public void manyCalls(int n)
        for (int i = 0; i < n; i++) 
            callAmethod();
        
    
    public void callAmethod()
        aProtectedMethod();
    
    protected void aProtectedMethod()
        int a=0;
        for (int i = 0; i < 5; i++) 
            a++;
        
    


public static class ChildrenClassA extends ParentClassA        


public static class ChildrenClassB extends ParentClassB        


【问题讨论】:

你打了两次电话。错字还是错误? 我的错误...我更新了代码和性能结果。谢谢。 【参考方案1】:

您认为下面提到的测试是否足够稳健以进行比较?

坦率地说,没有。

微基准测试很棘手; here 是关于它们的一个很好的讨论。就个人而言,我总是添加预热时间(例如,我运行一个方法的前 x 次不计入性能,给各种单例一个初始化的机会,并给 JIT 编译器时间来发挥它的魔力),我确保运行带有-server 开关的JVM。另外,我怀疑编译器可能足够聪明,可以删除 a++ 操作,因为它们的结果不会去任何地方。

但无论您的基准测试是否正确,我强烈相信 私有方法与受保护方法是一个设计问题。两者之间可能的性能差异应该对方法是私有还是受保护的决定没有任何影响

【讨论】:

当然,如果您正在测试客户端 JVM 的启动时间,您不需要预热或-server【参考方案2】:

最好不要将好的设计与性能要求混为一谈。

你应该从什么是好的设计开始,如果你不能同意,你必须接受它可能并不重要。尝试使用性能比较来找到一些衡量的选择差异的方法几乎总是错误的,因为您不知道性能差异是否重要。

我建议您允许每个开发人员遵循自己的风格,除非有很好的理由可以同意,而不是做某事。

【讨论】:

【参考方案3】:

私有方法是非虚拟的,因此调用它们的开销会少一点。

但是您的基准测试存在缺陷。从一个信封的背面,1,000,000,000 个电话在 8,000,000 微秒内完成。对于带有循环的方法,这是 8 ns。 HotSpot 能够合理地内联虚拟方法调用。热身后您的代码会更好,重复几次并查看变化以及平均值。此外,如果你交错算法,HotSpot 可能不得不在你交换时感到悲观。

更重要的是,受保护是邪恶的。

【讨论】:

【参考方案4】:

我更喜欢私有方法有两个原因:

封装:尽可能保持隐私。仅当方法确实要被覆盖时才使方法受到保护。也使重构和单元测试更容易,因为您可以重命名/移动/拆分/等。私有方法,不会在代码库的其他任何地方产生任何副作用。 优化:JIT 编译器更容易优化私有方法(内联等),因为它知道它不会在任何地方被覆盖。

【讨论】:

我不相信客户端或服务器 HotSpot 特别关心该方法是否是私有的以检测它是否被覆盖。客户端记录是否有任何加载的类覆盖。服务器比这更聪明。 我的意思是你可能认为一个方法永远不会被覆盖,你的一个用户可能希望这样做...... optimization?你有任何来源/参考吗?

以上是关于与java中的私有/受保护方法相关的性能与设计[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Java程序设计类与对象的基本概念(下)

Objective-C - 私有与受保护与公共

受保护的与私有的析构函数

201771010126 王燕《面向对象程序设计(Java)》第七周实验总结

我应该对私有/受保护方法进行单元测试吗

201771010106东文财《面向对象程序设计(java)》 实验7程序附加题