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

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

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

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


当前回答

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

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

其他回答

静态变量最重要的是会造成数据安全性问题(任何时间更改,任何人都可以更改,直接访问而不需要对象等)。

欲了解更多信息,请阅读这篇文章 谢谢。

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

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

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

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

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

有人可能会建议,在使用静态变量的大多数情况下,您确实希望使用单例模式。

全局状态的问题在于,有时在简单的上下文中作为全局是有意义的,但在实际的上下文中需要更加灵活,这就是单例模式变得有用的地方。

a)关于程序的原因。

如果你有一个小型到中型的程序,其中静态变量Global。Foo被访问,对它的调用通常不知道从哪里来——没有路径,因此也没有时间轴,变量是如何到达这个地方的,它在哪里被使用。现在我怎么知道是谁设置了它的实际值呢?如果我现在修改它,我怎么知道会发生什么呢?我让grep覆盖整个源代码,收集所有访问,知道发生了什么。

如果你知道如何使用它,因为你只是写了代码,问题是看不见的,但如果你试着理解外国代码,你就会明白。

b)你真的只需要一个吗?

静态变量通常会阻止相同类型的多个程序在相同JVM中运行,但它们的值不同。您通常无法预见在哪些情况下您的程序的多个实例是有用的,但是如果它发展了,或者如果它对其他人有用,他们可能会遇到这样的情况,他们想要启动您的程序的多个实例。

只有那些在较长时间内不会被很多人密集使用的或多或少无用的代码才可能适合使用静态变量。

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

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

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

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

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

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

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

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

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

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