gpt4 book ai didi

java - Java 方法是否应该默认是静态的?

转载 作者:IT老高 更新时间:2023-10-28 13:52:47 26 4
gpt4 key购买 nike

假设您正在 A 类中编写方法 foo()。foo 永远不会访问 A 的任何状态。您对 foo 的作用或行为方式一无所知。它可以做任何事情。

foo 是否应该始终是静态的,而不考虑其他任何因素?为什么不呢?

似乎我的类(class)总是在积累许多私有(private)辅助方法,因为我将任务分解并应用了只写一次的原则。其中大多数不依赖于对象的状态,但在类自己的方法之外永远不会有用。默认情况下它们应该是静态的吗?以大量内部静态方法告终是不是错了?

最佳答案

要回答标题上的问题,一般情况下,Java 方法应该默认是静态的。 Java 是一种面向对象的语言。

但是,你所说的有点不同。您专门谈到了辅助方法。

对于仅将值作为参数并返回值而不访问状态的辅助方法,它们应该是静态的。私有(private)的和静态的。让我强调一下:

Helper methods that do not access state should be static.


1。主要优点:代码更具表现力。

将这些方法设为静态至少有一个主要优势:您可以在代码中完全明确方法不需要知道任何实例状态。。 p>

代码不言自明。对于将阅读您的代码的其他人来说,事情变得更加明显,甚至在未来的某个时候对您来说也是如此。

2。另一个优点:代码可以更简单地推理。

如果您确定该方法不依赖于外部或全局状态,那么它就是一个纯函数,即数学意义上的函数:对于相同的输入,你可以肯定得到始终相同的输出。

3。优化优势

如果方法是静态的并且是纯函数,那么在某些情况下它可能是 memoized 获得一些性能提升(改变使用更多内存)。

4。字节码级差异

在字节码层面,如果将辅助方法声明为实例方法或静态方法,则会得到两个完全不同的东西。

为了让本节更容易理解,我们举个例子:

public class App {
public static void main(String[] args) {
WithoutStaticMethods without = new WithoutStaticMethods();
without.setValue(1);
without.calculate();

WithStaticMethods with = new WithStaticMethods();
with.setValue(1);
with.calculate();
}
}

class WithoutStaticMethods {

private int value;

private int helper(int a, int b) {
return a * b + 1;
}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}

public int calculate() {
return helper(value, 2 * value);
}
}

class WithStaticMethods {

private int value;

private static int helper(int a, int b) {
return a * b + 1;
}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}

public int calculate() {
return helper(value, 2 * value);
}
}

我们感兴趣的行是对 WithoutStaticMethodsWithStaticMethods 类上的 helper(...) 的调用。

没有静态方法

在第一种情况下,没有静态方法,当您调用辅助方法时,JVM 需要推送对实例的引用以将其传递给 invokespecial。看一下calculate()方法的代码:

 0 aload_0
1 aload_0
2 getfield #2 <app/WithoutStaticMethods.value>
5 iconst_2
6 aload_0
7 getfield #2 <app/WithoutStaticMethods.value>
10 imul
11 invokespecial #3 <app/WithoutStaticMethods.helper>
14 ireturn

0(或1)处的指令,aload_0,会将引用加载到堆栈中,稍后将被invokespecial使用。该指令将该值作为 helper(...) 函数的第一个参数,并且从未使用过,正如我们在此处看到的:

0 iload_1
1 iload_2
2 imul
3 iconst_1
4 iadd
5 ireturn

看到没有 iload_0 了吗?它被不必要地加载了。

使用静态方法

现在,如果你声明辅助方法是静态的,那么 calculate() 方法将如下所示:

 0 aload_0
1 getfield #2 <app/WithStaticMethods.value>
4 iconst_2
5 aload_0
6 getfield #2 <app/WithStaticMethods.value>
9 imul
10 invokestatic #3 <app/WithStaticMethods.helper>
13 ireturn

区别在于:

  • 少了一条aload_0指令
  • 现在使用 invokestatic
  • 调用辅助方法

嗯,辅助函数的代码也有点不同:没有 this 作为第一个参数,所以参数实际上在位置 0 和 1,我们可以在这里看到:

0 iload_0
1 iload_1
2 imul
3 iconst_1
4 iadd
5 ireturn

结论

从代码设计的角度来看,将辅助方法声明为静态更有意义:代码自己说话,它包含更多有用的信息。它声明它不需要实例状态来工作。

在字节码级别,发生了什么更加清楚,并且没有无用的代码(虽然我相信 JIT 无法优化它,但不会产生显着的性能成本)。

关于java - Java 方法是否应该默认是静态的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3346764/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com