我是一名Java程序员,刚进入企业界。最近我用Groovy和Java开发了一个应用程序。在我编写的所有代码中,都使用了相当多的静态元素。高级技术人员要求我减少使用的静态数据的数量。我在谷歌上搜索过相同的内容,我发现许多程序员都相当反对使用静态变量。

我发现静态变量使用起来更方便。而且我假定它们也是有效的(如果我错了请纠正我),因为如果我必须在一个类中对一个函数进行10,000次调用,我将很高兴使方法静态,并在其上使用直接的class . methodcall(),而不是用10,000个类实例使内存混乱,对吗?

此外,静态减少了对代码其他部分的相互依赖。他们可以作为完美的国家持有者。除此之外,我还发现一些语言(如Smalltalk和Scala)广泛地实现了静态。那么为什么程序员普遍反对静态(尤其是在Java世界中)呢?

PS:如果我对静态数据的假设是错误的,请纠正我。


当前回答

我的美元。这些答案中有几个混淆了这个问题,而不是说“静态是坏的”,我认为更好的是谈论范围和实例。

我想说的是,静态变量是一个“类”变量——它表示一个值,该值在该类的所有实例中共享。通常情况下,它也应该以这种方式确定作用域(对类及其实例进行保护或私有)。

如果您计划在它周围放置类级行为,并将其暴露给其他代码,那么单例可能是未来支持更改的更好解决方案(正如@Jessica所建议的那样)。这是因为您可以在实例/单例级别使用无法在类级别使用的接口——特别是继承。

关于为什么我认为其他答案中的某些方面不是问题的核心……

静态数据不是“全局的”。在Java中,作用域与静态/实例是分开控制的。

并发性对于静态方法的危险并不比实例方法小。它仍然是需要保护的州。当然,你可能有1000个实例,每个实例变量只有一个静态变量,但如果访问它们的代码不是以线程安全的方式编写的,你仍然会被搞砸——只是你可能需要更长的时间才能意识到这一点。

管理生命周期是一个有趣的论点,但我认为它不那么重要。我不明白为什么管理一对类方法(如init()/clear())比创建和销毁一个单例实例更难。事实上,有些人可能会说,由于GC的存在,单例更复杂一些。

PS,就Smalltalk而言,它的许多方言确实有类变量,但在Smalltalk中,类实际上是元类的实例,所以它们实际上是元类实例上的变量。尽管如此,我还是会运用同样的经验法则。如果它们被用于跨实例的共享状态,那么ok。如果它们支持公共功能,你应该考虑单例。唉,我真的很想念Smalltalk....

其他回答

在我看来,你是在问静态变量,但你也在你的例子中指出了静态方法。

静态变量并不是邪恶的——它们被采用为全局变量,就像大多数情况下与最终修饰符结合的常量一样,但正如它所说的,不要过度使用它们。

静态方法又名实用方法。使用它们通常不是一个坏的做法,但主要的问题是它们可能阻碍测试。

作为一个伟大的java项目的例子,使用了大量的静态和做它的正确方式,请看看Play!框架。在SO中也有关于它的讨论。

与静态导入相结合的静态变量/方法也被广泛应用于方便java中声明性编程的库中,如:make it easy或Hamcrest。如果没有大量的静态变量和方法,这是不可能的。

所以静态变量(和方法)很好,但要明智地使用它们!

邪恶是一个主观的术语。

你不能从创建和破坏的角度来控制静态。他们按照程序的要求生活装卸。

由于静态对象存在于一个空间中,所有希望使用它们的线程都必须通过您必须管理的访问控制。这意味着程序更加耦合,这种变化更难想象和管理(就像J Skeet说的那样)。这导致了隔离变更影响的问题,从而影响了如何管理测试。

这是我对他们的两个主要问题。

静态变量没有好坏之分。它们表示描述整个类而不是特定实例的属性。如果需要为某个类的所有实例设置一个计数器,则静态变量将是保存该值的合适位置。

当您尝试使用静态变量来保存与实例相关的值时,就会出现问题。

我只是对回答中的一些观点进行了总结。如果你发现任何错误,请随时改正。

伸缩性:每个JVM只有一个静态变量实例。假设我们正在开发一个图书馆管理系统,我们决定将book的名称作为一个静态变量,因为每本书只有一个。但是如果系统增长了,我们使用了多个jvm,那么我们就没有办法知道我们在处理哪本书了?

线程安全:在多线程环境中使用实例变量和静态变量都需要控制。但对于实例变量,它不需要保护,除非它在线程之间显式地共享,但对于静态变量,它总是由进程中的所有线程共享。

测试:虽然可测试的设计并不等于好的设计,但我们很少会看到一个好的设计是不可测试的。由于静态变量代表全局状态,因此测试它们非常困难。

关于状态的推理:如果我创建一个类的新实例,那么我们可以推理这个实例的状态,但如果它有静态变量,那么它可以处于任何状态。为什么?因为静态变量可能已经被一些不同的实例修改过,因为静态变量是跨实例共享的。

序列化:序列化也不能很好地与它们一起工作。

创建和销毁:静态变量的创建和销毁是无法控制的。通常它们在程序加载和卸载时被创建和销毁。这意味着它们不利于内存管理,还会在启动时增加初始化时间。

但如果我们真的需要它们呢?

但有时我们可能真的需要它们。如果我们真的觉得需要在应用程序中共享许多静态变量,那么一种选择是使用单例设计模式,它将拥有所有这些变量。或者我们可以创建一些对象,它有这些静态变量,可以被传递。

同样,如果静态变量被标记为final,它就变成了一个常量,赋给它一次的值就不能改变了。这意味着它将把我们从由于其可变性而面临的所有问题中拯救出来。

以上所有答案都说明了为什么静态方法很糟糕。它们是邪恶的原因是因为它给人一种错误的印象,即你在编写面向对象的代码,而事实上你并不是。 这简直是邪恶。