使用静态私有方法真的比实例私有方法更快/更好吗?

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

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,因为对我来说似乎更自然。

那么第一种方法和第二种方法之间是否存在样式/惯例/性能差异?

谢谢,


如评论中所建议的,我进行了测试,在我的基准测试中,动态方法更快。

这是测试代码:

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毫秒。然而,对我来说这并不具有决定性意义,因为我不知道编译器何时以及如何进行优化。这正是我试图找出的。

9
你试过它吗?速度更快了吗? - Alnitak
1
我认为速度差异(无论是什么)不值得以更易读的那个为代价。 - David
1
这与性能无关,但如果您想对代码进行单元测试,使用静态方法是一个不好的选择。https://dev59.com/Gmgu5IYBdhLWcg3wFDRr - naomi
1
@david99world,哪个更易读? - Simeon
3
我认为这并不是情况,因为private方法本质上也是final的,因此和static方法一样可以被静态调用和内联化。 - Theodoros Chatzigiannakis
显示剩余6条评论
8个回答

7

性能方面:如果有的话,差异可以忽略不计。

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


同意,我进行了测试,没有显著的差异。 - CsBalazsHungary
1
我想指出,私有方法与静态方法具有相同的性能,因为它们可以在编译时确定(编译器知道私有方法不会被覆盖)。如果将方法标记为公共方法,则分派将在运行时进行,并且比静态方法慢(尽管差距很小)。 - Vinicius Seufitele

2
如果你的方法需要实例数据或调用其他实例方法,那么它必须是实例方法。
如果函数仅仅依赖于它的参数,并且没有其他静态数据,那么它也可能是一个实例方法——在调用静态函数时可以避免重复类名。
我认为,除非满足以下条件,否则没有必要将函数设为static
  1. 它可以被其他类调用(即不是private),并且
  2. 它不引用实例变量,并且
  3. 它引用其他静态类数据

它仅使用参数(正如我在代码片段中所示),而不是其他方式。这不是我的问题的内容 :) - Simeon
1
所以把它设为静态的,不必担心(几乎可以肯定)会带来可忽略的性能差异。 - Alnitak
我并不担心 :) 我只是想知道是否有所不同。在我看来,“别担心”仍然不是一个答案。 - Simeon
@Alnitak,我会在您的清单中添加另外两个标准: 3. 您不打算为单元测试创建桩件,4. 有充分的理由不将其设置为其主参数类的实例方法。 - naomi

2
如果函数的结果只与参数有关,则应将其定义为静态函数。如果它依赖于实例,则应将其定义为实例成员。
这不是关于性能的问题,而是关于语义的问题。除非您每秒钟调用此函数一百万次,否则您不会注意到性能差异,即使如此,差异也不会很大。

2

这完全取决于上下文。通常,静态方法/变量是在类中声明的,以便外部类可以利用它们。

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

顺便说一下,从实例方法调用静态方法的语法不正确。您必须提供类名。


你对编码风格的观点是正确的,但这与问题无关。 - Simeon
1
我同意,这就是为什么我把它作为一个FYI发布的原因。 - Nilesh Tailor

2
据我所知,静态方法的绑定与非静态私有方法即早期绑定是相同的。
编译器在创建字节码时实际上会将方法的代码(静态或非静态私有)添加到您的代码中。 更新:刚看到这篇文章。它说实例方法绑定是动态的,因此如果方法不是非静态私有,那么您的静态方法更快

这种类型的答案是我正在寻找的。谢谢。 - Simeon
2
不完全相同。实例方法在运行时涉及更多查找正确函数的工作,除非该方法或类为“final”。 - cHao
2
@cHao,你是对的,但私有非静态方法使用静态/早期绑定 - Amandeep Jiddewar

2
“它可能是,也可能不是。在你的代码的不同执行之间可能会有所不同。”
“以下是您可以在不深入研究Hotsport代码(或非Hotspot JVM代码)的情况下了解到的唯一事情:”
  • 静态方法使用invokestatic调用,不需要对象引用。
  • 实例私有方法使用invokespecial调用,需要对象引用。
“这两个操作码都有一个解析要调用的实际方法的过程,这些过程相对类似(您可以阅读规范)。如果不计算实际实现的指令,就无法说哪个更快。”
invokespecial在堆栈上推送额外的值。完成此操作所需的时间以纳秒为单位计算。”
而且,所有这些都无关紧要,Hotspot有广泛的优化可供执行。在您的程序运行期间,它可能不必执行实际的方法解析超过一次。它可能选择内联方法(或者可能不选择),但这个成本大致相当。

1
我参加编程竞赛时发现,非静态方法比静态方法更快(虽然只是轻微的差别)。当然,这取决于你的使用情况和需求,但与非静态方法相比,静态方法的性能较差。按照惯例,你可以使用静态方法来简化代码,但创建一个类的实例并调用该方法将提供更好的性能表现。

1

我检查了一下,希望它能够回答你的问题,但代码并不美观:

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;
}
}

结果:

priv : 1774
privstat : 1736

priv : 1906
privstat : 1783

priv : 1963
privstat : 1751

priv : 1782
privstat : 1929

priv : 1876
privstat : 1867

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


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