问题描述
假设您在A类中编写方法 foo()
,foo不会访问任何A的状态。你对foo的作用或行为方式一无所知。它可以做任何事情。
Say you're writing method foo()
in class A. foo doesn't ever access any of A's state. You know nothing else about what foo does, or how it behaves. It could do anything.
如果foo始终是静态的,无论其他什么考虑因素?为什么不呢?
Should foo always be static, regardless of any other considerations? Why not?
似乎我的类总是在积累许多私有帮助器方法,因为我将任务分解并应用了only-write-it-once原则。其中大多数不依赖于对象的状态,但在类自己的方法之外永远不会有用。它们默认是静态的吗?结束大量内部静态方法是错误的吗?
It seems my classes are always accumulating many private helper methods, as I break tasks down and apply the only-write-it-once principle. Most of these don't rely on the object's state, but would never be useful outside of the class's own methods. Should they be static by default? Is it wrong to end up with a large number of internal static methods?
推荐答案
要回答关于标题的问题,一般来说,Java方法默认情况下不应该是静态的。 Java是一种面向对象的语言。
To answer the question on the title, in general, Java methods should not be static by default. Java is an object-oriented language.
然而,你所谈论的是有点不同。你特别谈谈辅助方法。
However, what you talk about is a bit different. You talk specifically of helper methods.
对于辅助方法,只需将值作为参数并返回一个值,而不访问状态,他们 应该是静态的 。私人和静态。让我强调一下:
In the case of helper methods that just take values as parameters and return a value, without accessing state, they should be static. Private and static. Let me emphasize it:
1。主要优点:代码更具表现力。
将这些方法设为静态至少具有一个主要优势:在代码中使其完全明确 该方法不需要知道任何实例状态。
代码说明了一切。对于那些将会阅读您的代码的人来说,事情变得更加明显,甚至在将来的某些时候也会对您有所帮助。
The code speaks for itself. Things become more obvious for other people that will read your code, and even for you in some point in the future.
如果你确定方法不依赖于外部或全局状态,那么它是纯函数,即数学意义上的函数:对于相同的输入,您可以确定获得始终相同的输出。
If you make sure the method does not depend on external or global state, then it is a pure function, ie, a function in the mathematical sense: for the same input, you can be certain to obtain always the same output.
如果方法是静态的并且是纯函数,那么在某些情况下它可能是 以获得一些性能提升(更改使用更多内存)。
If the method is static and is a pure function, then in some cases it could be memoized to obtain some performance gains (in change of using more memory).
在字节码级别,如果将辅助方法声明为实例方法或静态方法,则会获得两个完全不同的东西。
At the bytecode level, if you declare the helper method as an instance method or as a static method, you obtain two completely different things.
为了使本节更容易理解,让我们使用一个例子:
To help make this section easier to understand, let's use an example:
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);
}
}
我们感兴趣的行是对帮助(...)关于类 WithoutStaticMethods
和 WithStaticMethods
。
The lines we are interested in are the calls to helper(...)
on the classes WithoutStaticMethods
and WithStaticMethods
.
在第一种情况下,没有静态方法,当你调用helper方法时JVM需要将对实例的引用推送到 invokespecial
。看一下 calculate()
方法的代码:
In the first case, without static methods, when you call the helper method the JVM needs to push the reference to the instance to pass it to invokespecial
. Take a look at the code of the calculate()
method:
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(...)
函数的第一个参数,并且从不使用它,如下所示:
The instruction at 0 (or 1), aload_0
, will load the reference to the instance on the stack, and it will be consumed later by invokespecial
. This instruction will put that value as the first parameter of the helper(...)
function, and it is never used, as we can see here:
0 iload_1
1 iload_2
2 imul
3 iconst_1
4 iadd
5 ireturn
看到没有 iload_0
?它已被不必要地加载。
See there's no iload_0
? It has been loaded unnecessarily.
现在,如果你声明了辅助方法,静态,那么 calculate()
方法将如下所示:
Now, if you declare the helper method, static, then the calculate()
method will look like:
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
指令 - 现在用<$ c调用辅助方法$ c> invokestatic
- there's one less
aload_0
instruction - the helper method is now called with
invokestatic
好吧,帮助函数的代码也有点不同:有没有这个
作为第一个参数,因此参数实际上位于0和1位置,我们可以在这里看到:
Well, the code of the helper function is also a little bit different: there's no this
as the first parameter, so the parameters are actually at positions 0 and 1, as we can see here:
0 iload_0
1 iload_1
2 imul
3 iconst_1
4 iadd
5 ireturn
结论
从代码设计的角度来看,它更有意义声明辅助方法是静态的:代码说明一切,它包含更多有用的信息。它声明它不需要实例状态。
Conclusion
From the code design angle, it makes much more sense to declare the helper method static: the code speaks for itself, it contains more useful information. It states that it does not need instance state to work.
在字节码级别,更清楚的是发生了什么,并且没有无用的代码(尽管如此)我相信JIT无法对其进行优化,不会产生显着的性能成本。)
At the bytecode level, it is much more clear what is happening, and there's no useless code (that, although I believe the JIT has no way to optimize it, would not incur a significant performance cost).
这篇关于Java方法默认是静态的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!