为什么静态变量被认为是邪恶的?

2022-08-31 04:10:14

我是一名Java程序员,对企业界是新手。最近,我使用Groovy和Java开发了一个应用程序。我写的代码使用了相当多的静态。高级技术批次要求我减少使用的静态数据的数量。我在谷歌上搜索过同样的东西,我发现许多程序员都相当反对使用静态变量。

我发现静态变量使用起来更方便。而且我认为它们也是有效的(如果我错了,请纠正我),因为如果我必须对类中的函数进行10,000次调用,我很乐意使该方法保持静态并使用直接的方法,而不是用10,000个类的实例来混乱内存,对吧?Class.methodCall()

此外,静态减少了对代码其他部分的相互依赖性。他们可以充当完美的国家持有者。除此之外,我发现静态在一些语言中得到了广泛的实现,比如SmalltalkScala。那么,为什么这种对静态的反对在程序员中很普遍(特别是在Java世界中)呢?

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


答案 1

静态变量表示全局状态。这很难推理,也很难测试:如果我创建一个对象的新实例,我可以在测试中推理它的新状态。如果我使用使用静态变量的代码,它可以处于任何状态 - 并且任何东西都可以修改它。

我可以继续很长一段时间,但要考虑的更大的概念是,某事的范围越窄,就越容易推理。我们善于思考小事情,但如果没有模块化,就很难推断出百万线系统的状态。顺便说一句,这适用于各种事物 - 而不仅仅是静态变量。


答案 2

它不是很面向对象:statics可能被某些人认为是“邪恶的”,一个原因是它们与面向对象的范式背道而驰。特别是,它违反了数据封装在对象(可以扩展,信息隐藏等)中的原则。静态,在你描述使用它们的方式中,本质上是将它们用作全局变量,以避免处理诸如范围之类的问题。但是,全局变量是过程式或命令式编程范式的定义特征之一,而不是“好的”面向对象代码的特征。这并不是说过程范式不好,但我得到的印象是,你的主管希望你编写“好的面向对象代码”,而你真的想写“好的过程代码”。

当你开始使用静态时,Java中有许多gothiyas并不总是很明显。例如,如果在同一 VM 中运行两个程序副本,它们是否会粉碎静态变量的值并弄乱彼此的状态?或者,在扩展类时会发生什么,是否可以重写静态成员?VM 的内存不足是否因为静态数据数量过多,并且无法为其他需要的实例对象回收内存?

对象生存期:此外,静态数据的生存期与程序的整个运行时相匹配。这意味着,即使使用完类,也无法对所有这些静态变量中的内存进行垃圾回收。例如,如果您使变量成为非静态变量,并且在 main() 函数中创建了类的单个实例,然后要求类执行特定函数 10,000 次,一旦完成这 10,000 次调用,并且您删除了对单个实例的引用,则所有静态变量都可以被垃圾回收并重用。

防止某些重复使用:此外,静态方法不能用于实现接口,因此静态方法可以阻止某些面向对象的功能可用。

其他选项:如果效率是你主要关心的问题,那么可能还有其他更好的方法来解决速度问题,而不是只考虑调用通常比创建更快的优势。考虑在任何地方是否需要瞬态或易失性修饰符。为了保持内联能力,可以将方法标记为 final 而不是 static。方法参数和其他变量可以标记为 final,以允许某些编译器根据关于什么可以更改这些变量的假设进行优化。一个实例对象可以多次重用,而不是每次都创建一个新实例。通常,可能应为应用启用编译器优化开关。也许,应该设置设计,以便10,000次运行可以多线程并利用多处理器内核。如果portablity不是一个问题,也许原生方法会让你比静态方法更好的速度。

如果由于某种原因你不希望一个对象的多个副本,单例设计模式,比静态对象有优势,比如线程安全(假设你的单例编码得很好),允许延迟初始化,保证对象在使用时已经正确初始化,子类,测试和重构代码的优势,更不用说,如果你在某些时候改变主意只想要一个对象的一个实例,那就容易多了。删除代码以防止重复实例,而不是重构所有静态变量代码以使用实例变量。我以前不得不这样做,这并不好玩,你最终不得不编辑更多的类,这增加了你引入新错误的风险......第一次就把事情“正确”设置好要好得多,即使它似乎有其缺点。对我来说,如果你决定需要一些东西的多个副本,所需的返工可能是尽可能少地使用静态的最令人信服的理由之一。因此,我也不同意你关于静态技术减少相互依赖关系的说法,我认为,如果你有大量可以直接访问的静态数据,而不是一个“知道如何做某事”的对象,你最终会得到更多耦合的代码。


推荐