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

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

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

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


当前回答

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

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

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

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

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

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

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

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

其他回答

如果我必须在一个类中对一个函数进行10,000次调用,我会 很高兴使方法静态和使用直接 使用class.methodCall()来代替内存中10,000的混乱 类的实例,对吧?

您必须平衡将数据封装到具有状态的对象中的需求,以及简单地计算某些数据上的函数的结果的需求。

此外,静态减少了对代码其他部分的相互依赖。

封装也是如此。在大型应用程序中,静态方法往往会产生意大利面条式的代码,并且不容易进行重构或测试。

其他答案也为反对过度使用静态数据提供了很好的理由。

假设您有一个拥有许多用户的应用程序,并且您已经定义了一个静态函数,该函数将状态保存在一个静态变量中,那么每个用户都将修改其他用户的状态。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

从我的观点来看,静态变量应该只读取数据或变量创建的约定。

For example we have a ui of some project, and we have a list of countries, languages, user roles, etc. And we have class to organize this data. we absolutely sure that app will not work without this lists. so the first that we do on app init is checking this list for updates and getting this list from api (if needed). So we agree that this data is "always" present in app. It is practically read only data so we don't need to take care of it's state - thinking about this case we really don't want to have a lot of instances of those data - this case looks a perfect candidate to be static.