Java 如果私有辅助方法可以是静态的,它们是否应该是静态的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/538870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:58:38  来源:igfitidea点击:

Should private helper methods be static if they can be static

javastaticmethodsstatic-methods

提问by avalys

Let's say I have a class designed to be instantiated. I have several private "helper" methods inside the class that do not require access to any of the class members, and operate solely on their arguments, returning a result.

假设我有一个旨在实例化的类。我在类中有几个私有的“帮助器”方法,它们不需要访问任何类成员,并且只对它们的参数进行操作,返回结果。

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne(member);
       total += computeMore(member);
       return total;         
   }

   private double computeOne(Something arg) { ... }
   private double computeMore(Something arg) {... } 
} 

Is there any particular reason to specify computeOneand computeMoreas static methods - or any particular reason not to?

是否有任何特别的理由指定computeOnecomputeMore作为静态方法 - 或者有什么特别的理由不这样做?

It is certainly easiest to leave them as non-static, even though they could certainly be static without causing any problems.

将它们保留为非静态当然是最容易的,即使它们当然可以是静态的而不会造成任何问题。

采纳答案by Esko Luontola

I prefer such helper methods to be private static; which will make it clear to the reader that they will not modify the state of the object. My IDE will also show calls to static methods in italics, so I will know the method is static without looking the signature.

我更喜欢这样的辅助方法private static;这将使读者清楚他们不会修改对象的状态。我的 IDE 还会以斜体显示对静态方法的调用,因此我无需查看签名就知道该方法是静态的。

回答by Steve B.

My personal preference would be to declare them static, as it's a clear flag that they're stateless.

我个人的偏好是将它们声明为静态,因为这是一个明确的标志,表明它们是无状态的。

回答by Michael Myers

It might result in slightly smaller bytecode, since the static methods won't get access to this. I don't think it makes any difference in speed (and if it did, it would probably be too small to make a difference overall).

它可能会导致字节码稍小,因为静态方法无法访问this. 我不认为它对速度有任何影响(如果确实如此,它可能太小而无法整体产生差异)。

I would make them static, since I generally do so if at all possible. But that's just me.

我会让它们保持静态,因为如果可能的话,我通常会这样做。但这只是我。



EDIT:This answer keeps getting downvoted, possibly because of the unsubstantiated assertion about bytecode size. So I will actually run a test.

编辑:这个答案不断被低估,可能是因为关于字节码大小的未经证实的断言。所以我将实际运行一个测试。

class TestBytecodeSize {
    private void doSomething(int arg) { }
    private static void doSomethingStatic(int arg) { }
    public static void main(String[] args) {
        // do it twice both ways
        doSomethingStatic(0);
        doSomethingStatic(0);
        TestBytecodeSize t = new TestBytecodeSize();
        t.doSomething(0);
        t.doSomething(0);
    }
}

Bytecode (retrieved with javap -c -private TestBytecodeSize):

字节码(用 检索javap -c -private TestBytecodeSize):

Compiled from "TestBytecodeSize.java"
class TestBytecodeSize extends java.lang.Object{
TestBytecodeSize();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

private void doSomething(int);
  Code:
   0:   return

private static void doSomethingStatic(int);
  Code:
   0:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   invokestatic    #2; //Method doSomethingStatic:(I)V
   4:   iconst_0
   5:   invokestatic    #2; //Method doSomethingStatic:(I)V
   8:   new     #3; //class TestBytecodeSize
   11:  dup
   12:  invokespecial   #4; //Method "<init>":()V
   15:  astore_1
   16:  aload_1
   17:  iconst_0
   18:  invokespecial   #5; //Method doSomething:(I)V
   21:  aload_1
   22:  iconst_0
   23:  invokespecial   #5; //Method doSomething:(I)V
   26:  return

}

Invoking the static method takes two bytecodes (byteops?): iconst_0(for the argument) and invokestatic.
Invoking the non-static method takes three: aload_1(for the TestBytecodeSizeobject, I suppose), iconst_0(for the argument), and invokespecial. (Note that if these hadn't been private methods, it would have been invokevirtualinstead of invokespecial; see JLS §7.7 Invoking Methods.)

调用静态方法需要两个字节码(byteops?):(iconst_0对于参数)和invokestatic.
调用非静态方法需要三个:(aload_1对于TestBytecodeSize对象,我想)、iconst_0(对于参数)和invokespecial. (请注意,如果这些不是私有方法,它会invokevirtual代替invokespecial;请参阅JLS §7.7 调用方法。)

Now, as I said, I don't expect there to be any great difference in performance between these two, other than the fact that invokestaticrequires one fewer bytecode. invokestaticand invokespecialshould both be slightly faster than invokevirtual, since they both use static binding instead of dynamic, but I have no idea if either is faster than the other. I can't find any good references either. The closest I can find is this 1997 JavaWorld article, which basically restates what I just said:

现在,正如我所说的,除了invokestatic需要少一个字节码这一事实之外,我不希望这两者在性能上有任何大的差异。invokestatic并且invokespecial都应该比 略快invokevirtual,因为它们都使用静态绑定而不是动态绑定,但我不知道是否有一个比另一个快。我也找不到任何好的参考资料。我能找到的最接近的是这篇 1997 年的 JavaWorld 文章,它基本上重申了我刚才所说的内容:

The fastest instructions will most likely be invokespecialand invokestatic, because methods invoked by these instructions are statically bound. When the JVM resolves the symbolic reference for these instructions and replaces it with a direct reference, that direct reference probably will include a pointer to the actual bytecodes.

最快的指令很可能是invokespecialand invokestatic,因为这些指令调用的方法是静态绑定的。当 JVM 解析这些指令的符号引用并将其替换为直接引用时,该直接引用可能会包含一个指向实际字节码的指针。

But many things have changed since 1997.

但自 1997 年以来,很多事情都发生了变化。

So in conclusion... I guess I'm still sticking with what I said before. Speed shouldn't be the reason to choose one over the other, since it would be a micro-optimization at best.

所以总而言之......我想我仍然坚持我之前所说的。速度不应该成为选择另一个的原因,因为它充其量只是一种微优化。

回答by notnot

The static/non-static question comes down to "will I really need to use an object of this class"?

静态/非静态问题归结为“我真的需要使用此类的对象吗”?

So, are you passing the object between different methods? Does the object contain information that is useful outside the context of the static methods? Is there any reason not to define methods both ways if you'll use them both ways?

那么,您是否在不同的方法之间传递对象?对象是否包含在静态方法的上下文之外有用的信息?如果您同时使用它们,是否有任何理由不以两种方式定义方法?

If you're in this dilemma, it seems to me that you have all of the data required for the method floating around in your code outside of the object. Is this what you want? Would it be easier to just always collect that data into an object each time? You might just be ambivalent about committing to a single model. If you can do it all using one way, then pick either static or non-static and go with it.

如果您处于这种两难境地,在我看来,您拥有该方法所需的所有数据,这些数据都存在于对象之外的代码中。这是你想要的吗?每次总是将这些数据收集到一个对象中会更容易吗?您可能只是对致力于单一模型持矛盾态度。如果您可以使用一种方法完成所有操作,那么选择静态或非静态并使用它。

回答by Axelle Ziegler

I can't really think of clear advantages for private static method. That being said, there is no specific advantages to making them non-static either. It's mainly a matter of presentation : you might want to make them static to clearly underline the fact that they are not altering an object.

我真的想不出私有静态方法的明显优势。话虽如此,使它们非静态也没有特定的优势。这主要是一个演示问题:您可能希望使它们保持静态以清楚地强调它们不会改变对象的事实。

For method with different access privileges, I think there are two main arguments :

对于具有不同访问权限的方法,我认为有两个主要参数:

  • static methods can be called without creating an instance of an object, which can be useful
  • static methods can't be inherited, which can be a problem if you need polymorphism (but is irrelevant for private methods).
  • 可以在不创建对象实例的情况下调用静态方法,这很有用
  • 静态方法不能被继承,如果您需要多态,这可能是一个问题(但与私有方法无关)。

Besides that, the difference is pretty small, and I strongly doubt that the extra this pointer passed to instance method makes a significant difference.

除此之外,差异非常小,我强烈怀疑传递给实例方法的额外 this 指针会产生显着差异。

回答by notnot

More specifically to the example you've given, it seems that the purpose of defining these methods is more for code clarity when you're reading it than for functionality (they aredefined as private). In that case, going with static really does nothing for you, since the purpose of static is to expose class functionality.

更具体地说,对于您给出的示例,定义这些方法的目的似乎更多是为了在您阅读代码时使代码清晰,而不是为了功能(它们定义为私有)。在这种情况下,使用 static 对您来说真的没有任何作用,因为 static 的目的是公开类功能。

回答by Kip

If the method is basically just a subroutine that will never foreseeably use state information, declare it static.

如果该方法基本上只是一个永远不会使用状态信息的子程序,请将其声明为静态。

This allows it to be used in other static methods or in class initialization, i.e.:

这允许它在其他静态方法或类初始化中使用,即:

public class Example {
   //...

   //Only possible if computeOne is static
   public final static double COMPUTED_ONE = computeOne(new Something("1"));

   //...
}

回答by maxaposteriori

My preference in cases like these is to make computeOneand computeMorestatic methods. The reason: encapsulation. The less code which has access to the implementation of your class, the better.

在这种情况下,我更喜欢 makecomputeOnecomputeMorestatic 方法。原因:封装。可以访问您的类的实现的代码越少越好。

In the example you give, you state that computeOneand computeMoreshouldn't need to access the internals of the class, so why give the opportunity for maintainers of the class to meddle with the internals.

在您给出的示例中,您声明computeOne并且computeMore不需要访问类的内部结构,那么为什么要给该类的维护者机会来干预内部结构呢?

回答by Uri

I would declare them as static to flag them as stateless.

我会将它们声明为静态以将它们标记为无状态。

Java does not have a better mechanism for minor operations that aren't exported, so I think private static is acceptable.

Java 对于不导出的次要操作没有更好的机制,所以我认为私有静态是可以接受的。

回答by Powerlord

The answer is... it depends.

答案是……视情况而定。

If member is an instance variable specific to the object you're dealing with, then why pass it as a parameter at all?

如果 member 是特定于您正在处理的对象的实例变量,那么为什么将它作为参数传递呢?

For instance:

例如:

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne();
       total += computeMore();
       return total;         
   }

   private double computeOne() { /* Process member here */ }
   private double computeMore() { /* Process member here */ } 
}