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

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) {... } 
} 

是否有特别的理由指定computeOne和computeMore作为静态方法-或者有特别的理由不这样做?

当然,让它们保持非静态状态是最简单的,尽管它们当然可以是静态的,而不会引起任何问题。


当前回答

或者有什么特别的理由不(将它们声明为静态的)?

Yes.

通过将它们保留为实例方法,您可以在以后提供不同的实现。

这听起来可能很愚蠢(实际上如果这些方法只由您在50行程序中使用,则会很愚蠢),但在较大的应用程序中,或在其他人使用的库中,您可能会决定选择更好的实现,但又不想破坏现有代码。

因此,在新版本中创建一个子类并返回该子类,由于方法被声明为实例方法,因此只需让多态性完成它的工作。

此外,出于同样的原因,将构造函数设置为私有并提供静态工厂方法也会带来好处。

因此,我的建议是保留它们作为实例方法,并尽可能避免静态方法。 充分利用语言提供的动态特性。

请参见这里的相关视频:如何设计一个好的API以及为什么它很重要

虽然它与“静态vs实例”方法的讨论没有直接关系,但它涉及到API设计中一些有趣的点。

其他回答

答案是……视情况而定。

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

例如:

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 */ } 
}

我想澄清一些其他答案所说的事情,因为他们提供了我认为是错误的信息。

首先,因为方法是私有的,即使你声明它们是静态的,你也不能在这个类之外访问它们。其次,它们是私有的,所以你甚至不能在子类中重写,所以静态或非静态没有任何区别。第三,非静态的私有方法也可以从类的构造函数中调用,它不必是静态的。

现在回到您的问题,私有helper方法应该定义为静态还是非静态。我将采用Steve的回答,因为将私有方法标记为静态表明该方法是无状态的,因为我在编码时也遵循这一规则。

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

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

public class Example {
   //...

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

   //...
}

根据我的经验,我认为这种私有方法往往是相当通用和可重用的。

我认为要做的第一件事是问这个方法在当前类上下文之外是否有用。如果是这样,我将完全按照Everyone的建议,将这个方法作为静态提取到一些utils类,希望在实现新方法之前进行检查,做完全相同的事情。

这种通用的私有方法是项目中很大一部分代码重复的来源,因为每个开发人员都在需要使用它们的地方独立地重新发明它们。因此,这种方法的集中化是一条可行之路。

你可能想要声明静态帮助方法的一个原因是,如果你需要在类构造函数this或super之前调用它们。例如:

public class MyClass extends SomeOtherClass { 
    public MyClass(String arg) {
       super(recoverInt(arg));
    }

    private static int recoverInt(String arg) {
       return Integer.parseInt(arg.substring(arg.length() - 1));
    }
}

这是一个有点做作的例子,但显然在这种情况下,recoverInt不能是一个实例方法。