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

新手上路,请多包涵

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

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

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

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

原文由 Vamsi Emani 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 600
2 个回答

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

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

原文由 Jon Skeet 发布,翻译遵循 CC BY-SA 3.0 许可协议

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

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

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

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

其他选项: 如果效率是您最关心的问题,那么可能有其他更好的方法来解决速度问题,而不是仅考虑调用通常比创建更快的优势。考虑是否在任何地方都需要 transient 或 volatile 修饰符。为了保留内联的能力,可以将方法标记为 final 而不是 static。方法参数和其他变量可以标记为 final,以允许某些编译器根据可以更改这些变量的假设进行优化。实例对象可以多次重复使用,而不是每次都创建一个新实例。一般来说,可能应该为应用程序打开编译器优化开关。也许,应该设置设计,以便 10,000 次运行可以是多线程的,并利用多处理器内核。如果可移植性不是问题,也许本地方法可以使您获得比静态方法更快的速度。

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

原文由 Jessica Brown 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题