【问题标题】:Is using static private methods really faster/better than instance private methods?使用静态私有方法真的比实例私有方法更快/更好吗?
【发布时间】:2013-02-20 00:23:18
【问题描述】:

我要问的是这样做是否有区别:

public Something importantBlMethod(SomethingElse arg) {
    if (convenienceCheckMethod(arg)) {
        // do important BL stuff
    }
}

private boolean convenienceCheckMethod(SomethingElse arg) {
    // validate something
}

还有这个:

public Something importantBlMethod(SomethingElse arg) {
    if (convenienceCheckMethod(arg)) {
        // do important BL stuff
    }
}

private static boolean convenienceCheckMethod(SomethingElse arg) {
    // validate something
}

我实际上使用选项 1,因为它对我来说似乎更自然。

那么第一种和第二种方式之间是否存在风格/约定/性能差异?

谢谢,


正如我测试的 cmets 中所建议的,在我的基准测试中,动态方法更快。

这是测试代码:

public class Tests {

    private final static int ITERATIONS = 100000;

    public static void main(String[] args) {
        final long start = new Date().getTime();

        final Service service = new Service();
        for (int i = 0; i < ITERATIONS; i++) {

            service.doImportantBlStuff(new SomeDto());
        }

        final long end = new Date().getTime();

        System.out.println("diff: " + (end - start) + " millis");
    }
}

这是服务代码:

public class Service {

    public void doImportantBlStuff(SomeDto dto) {

        if (checkStuffStatic(dto)) {

        }

        // if (checkStuff(dto)) {

        // }
    }

    private boolean checkStuff(SomeDto dto) {
        System.out.println("dynamic");
        return true;
    }

    private static boolean checkStuffStatic(SomeDto dto) {
        System.out.println("static");
        return true;
    }
}

对于 100000 次迭代,动态方法通过了 577 毫秒,静态方法通过了 615 毫秒。

但这对我来说是不确定的,因为我不知道编译器决定优化什么以及何时决定。

这就是我想要找出的。

【问题讨论】:

  • 你试过了吗?是不是更快?
  • 我会说速度差异(无论是什么)都不值得权衡哪个更具可读性。
  • 这与性能无关,但如果你想对代码进行单元测试,使用静态方法是个坏主意stackoverflow.com/questions/11591564/…
  • @david99world 哪个更易读?
  • 我想说情况并非如此,因为private 方法本质上也是final,因此与static 方法一样可以静态调用和内联。

标签: java performance coding-style static-methods


【解决方案1】:

我参加了编码比赛,并且我观察到,非静态方法比静态方法更快(但最少)。当然,这取决于您的使用情况和情况要求,但与非静态方法相比,静态方法的性能较差。按照惯例,您可以使用静态方法来简化代码,但创建类的实例并调用该方法会提供更好的性能。

【讨论】:

    【解决方案2】:

    我查过了,希望它做你想知道的,代码不会很漂亮:

    public class main {
    
    @SuppressWarnings("all")
    public static void main(String[] args) {
        main ma = new main();
        int count = Integer.MAX_VALUE;
        long beg = (new Date()).getTime();
        for (int i = 0; i < count; i++) {
            ma.doNothing();
        }
        System.out.println("priv : " + new Long((new Date()).getTime() - beg).toString());
    
        beg = (new Date()).getTime();
        for (int i = 0; i < count; i++) {
            doNothingStatic();
        }
        System.out.println("privstat : " + new Long((new Date()).getTime() - beg).toString());
    
    }
    
    private void doNothing() {
        int i = 0;
    }
    
    private static void doNothingStatic() {
        int i = 0;
    }
    }
    

    结果:

    隐私:1774
    隐私统计:1736

    隐私:1906
    隐私统计:1783

    隐私 : 1963
    隐私统计:1751

    隐私:1782
    隐私统计:1929

    隐私:1876
    隐私统计:1867

    它看起来不像依赖于静态 - 非静态私有方法。我确信差异来自机器当前的负担。

    【讨论】:

      【解决方案3】:

      据我说 NO 静态方法的绑定与非静态私有相同,即early binding。 . 编译器实际上在创建字节码时将方法代码(静态或非静态私有)添加到您的代码中。

      更新:刚刚通过这个article。它说实例方法绑定是dynamic 所以如果方法不是non-static private 那么。您的静态方法更快

      【讨论】:

      • 我正在寻找这种类型的答案。谢谢。
      • 不太一样。实例方法在查找运行时调用的正确函数方面涉及更多内容,除非方法或类是final
      • @cHao 你是对的,但是私有非静态方法使用static/early binding
      【解决方案4】:

      可能会,也可能不会。您的代码的不同执行可能会有所不同。

      这是您在不深入研究 Hotsport 代码(或非 Hotspot JVM 的代码)的情况下知道的唯一一件事:

      • 静态方法使用invokestatic 调用,不需要对象引用。
      • 使用invokespecial 调用实例私有方法,这确实需要对象引用。

      这两个操作码都有一个用于解析要调用的实际方法的过程,并且这些过程相对相似(您可以阅读规范)。如果不计算实际实现的指令,就不可能说哪个更快。

      invokespecial 将一个额外的值压入堆栈。执行此操作的时间以几分之一纳秒计算。

      Hotspot 可以执行的优化范围很广。在程序运行期间,它可能不必多次执行实际的方法解析。它可能会选择内联该方法(也可能不内联),但成本将大致相等。

      【讨论】:

        【解决方案5】:

        如果您的方法需要实例数据或调用其他实例方法,则它必须是实例方法。

        如果函数依赖于它的参数,而不依赖于其他静态数据,那么它也可能是一个实例方法——你将避免在调用时需要重复类名静态函数。

        恕我直言,没有特别需要创建函数static,除非:

        1. 它可以从其他类调用(即不是private),并且
        2. 它不引用实例变量,并且
        3. 引用其他静态类数据

        【讨论】:

        • 它不只使用参数(正如我在代码 sn-p 中所示)。这不是我要问的:)
        • 所以让它成为静态的,不要担心(几乎可以肯定)可以忽略不计的性能差异。
        • 我不担心 :) 我想知道是否有区别。恕我直言,别担心仍然不是答案。
        • @Alnitak,我会在您的列表中添加更多标准:3. 您不打算将其存根用于单元测试,以及 4. 有充分的理由不做它是其主要参数类的实例方法。
        【解决方案6】:

        这一切都取决于上下文。通常静态方法/变量在类中声明,以便外部类可以使用它们。

        如果您正在调用本地方法,那么您通常应该使用实例方法而不是进行静态调用。

        仅供参考,您从实例方法调用静态方法的语法是错误的。您必须提供类名。

        【讨论】:

        • 您对编码风格的看法是正确的,但这与问题无关。
        • 我同意,这就是我将其作为 FYI 提出的原因。
        【解决方案7】:

        如果函数的结果除了参数不依赖于任何东西,它应该是静态的。如果它依赖于一个实例,则使其成为实例成员。

        这与性能无关;这是关于语义的。除非您每秒调用此函数一百万次,否则您不会注意到性能差异,即使这样差异也不大。

        【讨论】:

          【解决方案8】:

          性能方面:差异可以忽略不计。

          经验法则是,如果您的方法不与其类的任何成员交互,则将其声明为静态。

          【讨论】:

          • 同意,我测试了,没有显着差异。
          • 我想指出私有方法具有与静态相同的性能,因为它们可以在编译时确定(编译器知道私有方法不会被覆盖)。如果将方法标记为公共,则调度将在运行时进行,并且会比静态方法慢(尽管有一点差距)。
          猜你喜欢
          • 1970-01-01
          • 2013-09-25
          • 2012-07-14
          • 2010-11-04
          • 1970-01-01
          • 2017-05-23
          • 2013-11-20
          • 2017-06-11
          • 2022-11-20
          相关资源
          最近更新 更多