所有不使用实例变量的方法是否应标记为静态?

30

假设我有一个像这样的类:

public class Car {

    private double distanceDriven;

    public void drive(double miles){
        distanceDriven += miles;
    }

    public void driveInCanada(double kilometer){
        distanceDriven += convertToMiles(kilometer);
    }

    private double convertToMiles(double km){
        return km*0.621371192;
    }   
}

你可以看到convertToMiles

  • 没有使用任何实例变量
  • 只在类内部使用

它应该声明为静态吗?这并不影响函数的功能(如上所述)。我认为它可能会影响:

  • 可读性
  • 性能
  • 其他?

convertToMiles函数应该长成什么样子:

    private double convertToMiles(double km){
或者
    private static double convertToMiles(double km){

在C++中,这将改变调用的语法:您需要使用Car::convertToMiles(x)而不是mycar.convertToMiles(x)。我很好奇在Java中是否也是这种情况? - Mark Ransom
2
@Mark:他在谈论私有方法,在这种情况下从对象内部调用,调用语法不会改变。 - Ben Zotto
@quixoto,很好的观察 - 在C ++中也是如此。 - Mark Ransom
尽管作者可能希望得到一个确定的答案,但我认为这实际上更像是讨论而不是问题。就像所有旨在引发讨论的好问题一样,“答案取决于情况”。性能是否是一个问题?严格的面向对象编程是否是一个问题?(我知道有些人认为违反面向对象编程原则是一种罪过,但让我们面对现实,有时遵循某些原则并不是实际可行的。) - Trevor
6个回答

18
为了最大限度地保持样式卫生,是的,私有方法应该是静态的,这些方法不使用任何对象状态,只在对象内部有意义。
这是表明它们如何操作最清晰(严格)的方式,并且会有帮助地迫使您在方法边界周围进行设计时要小心,并且在以后决定更改其中之一以使用对象数据时三思而行。
值得一提的是,我不认为这里有相关的性能影响(理论上,由于没有隐式的“this”引用,静态方法更容易调用)。此外,在代码库中严格执行这一点可能会让你发疯,但这肯定是一个合理的目标。
请注意,公共方法在将它们标记为静态之前需要更多考虑;那些方法不能在以后更改而不影响调用者,因此,“默认紧密性”并不总是正确的选择。

6
如果你自己在问这个问题,那么你的设计已经摇摇欲坠了。你应该将所有那些“静态”函数从类中剥离出来,然后放到一个通用的、可重用的算法容器静态类中。
看看你的代码,convertToMiles 和汽车有什么关系?这是一个通用的算法,可以在多个函数中重用。

1
你的基本思路是认为所有私有静态方法都有问题吗?如果是这样,我很想听听如何考虑比这个例子不太琐碎的更详细信息。(如果不是,这可能更适合作为评论。)谢谢。 - Ben Zotto
1
不是所有的情况,但大多数情况下是这样的。我曾遇到过一些情况,在这些情况中,我编写了静态方法,实际上它是类逻辑的一部分,而没有使用它的状态,但这种情况非常罕见,而且显然不是 OP 的情况。 - Blindy

4
使用static可能会提高性能,但如果内联化,则不会被频繁调用,因此这种情况发生的可能性较小。 static很有用,因为它明确了您没有访问任何成员字段。过去我使用静态方法时就遇到了一些错误(因为它不应该使用成员字段),但现在这个问题已经解决了。
您可以通过设计添加层和复杂度,这可能有用,但我会遵循YANGI原则并说您不太可能想要更改如何将千米转换为英里,或者如果您确实更改它,则不太可能需要多种方法来完成。

4
所有这种方法都是明确的不允许的。
例如,如果这种方法只在其参数上计算结果(返回值),并且作者希望允许其他人在子类中更改计算方法(这是某种模板方法模式),那么这是完全合法的。-- 重写类只能在它们不是静态的情况下进行。
顺便说一句:如果你改变你的问题,只问私有方法,那么我不能用这种方式来辩论。但你问了所有类型的方法。

1
优秀的点,继承是我没有考虑过的一件事。我希望我能给这个点赞两次。然而,对于私有方法,这应该不重要。 - sixtyfootersdude

2

是的,尽可能使用静态方法。


1
使用静态方法可以防止子类覆盖它们,这限制了灵活性和可扩展性。 - Philipp Wendler
3
@Philipp 如果你需要覆盖一个方法,那么你不能将其设置为静态的。我说过“在你使用静态时使用它”。有时太多的灵活性是不好的。这就是为什么String类是final的原因。它通过设计来限制灵活性。 - Michał Šrajer

1
private static double convertToMiles(double km){}

这将是您的程序代码正确的选择,因为convertToMiles()方法与实例变量无关。
但请记住,如果非静态成员在其他类中重复使用此方法,则静态的目的不会被实现,因为静态避免多个对象的创建和内存浪费。

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