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

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

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

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


当前回答

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

我明白你的想法,但一个简单的单例模式将做同样的事情,而不必实例化10,000个对象。

可以使用静态方法,但只能用于与对象域相关且不需要或使用对象的内部属性的函数。

ex:

public class WaterContainer {
    private int size;
    private int brand;
    ...etc

    public static int convertToGallon(int liters)...

    public static int convertToLiters(int gallon)...

}

其他回答

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

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

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

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

这里有很多很好的答案,

记忆: 静态变量只要类加载器存在(通常直到VM死亡)就存在,但这只是在大块对象/引用存储为静态的情况下。

模块化: 考虑IOC、依赖注入、代理等概念。所有这些都完全反对紧密耦合/静态实现。

其他缺点:线程安全性,可测试性

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

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

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

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

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

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

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

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

Its not very object oriented: One reason statics might be considered "evil" by some people is they are contrary the object-oriented paradigm. In particular, it violates the principle that data is encapsulated in objects (that can be extended, information hiding, etc). Statics, in the way you are describing using them, are essentially to use them as a global variable to avoid dealing with issues like scope. However, global variables is one of the defining characteristics of procedural or imperative programming paradigm, not a characteristic of "good" object oriented code. This is not to say the procedural paradigm is bad, but I get the impression your supervisor expects you to be writing "good object oriented code" and you're really wanting to write "good procedural code".

在Java中,当您开始使用静态时,有许多并不总是立即明显的陷阱。例如,如果在同一个VM中运行两个程序副本,它们会共享静态变量的值并混淆彼此的状态吗?或者当你扩展类时会发生什么,你能重写静态成员吗?您的虚拟机内存不足,因为您有疯狂的静态数据,并且内存不能为其他需要的实例对象回收?

Object Lifetime: Additionally, statics have a lifetime that matches the entire runtime of the program. This means, even once you're done using your class, the memory from all those static variables cannot be garbage collected. If, for example, instead, you made your variables non-static, and in your main() function you made a single instance of your class, and then asked your class to execute a particular function 10,000 times, once those 10,000 calls were done, and you delete your references to the single instance, all your static variables could be garbage collected and reused.

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

Other Options: If efficiency is your primary concern, there might be other better ways to solve the speed problem than considering only the advantage of invocation being usually faster than creation. Consider whether the transient or volatile modifiers are needed anywhere. To preserve the ability to be inlined, a method could be marked as final instead of static. Method parameters and other variables can be marked final to permit certain compiler optimiazations based on assumptions about what can change those variables. An instance object could be reused multiple times rather than creating a new instance each time. There may be compliler optimization switches that should be turned on for the app in general. Perhaps, the design should be set up so that the 10,000 runs can be multi-threaded and take advantage of multi-processor cores. If portablity isn't a concern, maybe a native method would get you better speed than your statics do.

If for some reason you do not want multiple copies of an object, the singleton design pattern, has advantages over static objects, such as thread-safety (presuming your singleton is coded well), permitting lazy-initialization, guaranteeing the object has been properly initialized when it is used, sub-classing, advantages in testing and refactoring your code, not to mention, if at some point you change your mind about only wanting one instance of an object it is MUCH easier to remove the code to prevent duplicate instances than it is to refactor all your static variable code to use instance variables. I've had to do that before, its not fun, and you end up having to edit a lot more classes, which increases your risk of introducing new bugs...so much better to set things up "right" the first time, even if it seems like it has its disadvantages. For me, the re-work required should you decide down the road you need multiple copies of something is probably one of most compelling reasons to use statics as infrequently as possible. And thus I would also disagree with your statement that statics reduce inter-dependencies, I think you will end up with code that is more coupled if you have lots of statics that can be directly accessed, rather than an object that "knows how to do something" on itself.