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

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

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

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


当前回答

总结在Java中使用静态方法的几个基本优点和缺点:

优点:

全局可访问,即不与任何特定的对象实例绑定。 每个JVM一个实例。 可以通过类名访问(不需要对象)。 包含一个适用于所有实例的值。 在JVM启动时加载,并在JVM关闭时死亡。 它们不会修改Object的状态。

缺点:

Static members are always part of memory whether they are in use or not. You can not control creation and destruction of static variable. Usefully they have been created at program loading and destroyed when program unload (or when JVM shuts down). You can make statics thread safe using synchronize but you need some extra efforts. If one thread change value of a static variable that can possibly break functionality of other threads. You must know “static“ before using it. You cannot override static methods. Serialization doesn't work well with them. They don't participate in runtime polymorphism. There is a memory issue (to some extent but not much I guess) if a large number of static variables/methods are used. Because they will not be Garbage Collected until program ends. Static methods are hard to test too.

其他回答

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.

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

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

Static variables are generally considered bad because they represent global state and are therefore much more difficult to reason about. In particular, they break the assumptions of object-oriented programming. In object-oriented programming, each object has its own state, represented by instance (non-static) variables. Static variables represent state across instances which can be much more difficult to unit test. This is mainly because it is more difficult to isolate changes to static variables to a single test.

也就是说,区分常规静态变量(通常被认为是不好的)和最终静态变量(AKA常量;还不错)。

我玩过很多静力学,我可以给你一个稍微不同的答案——或者可能是稍微不同的看待它的方式吗?

当我在一个类中使用静态(成员和方法)时,我最终开始注意到我的类实际上是两个分担责任的类——“静态”部分很像单例,而非静态部分(普通类)。据我所知,你可以通过为一个类选择所有静态类,为另一个类选择所有非静态类来完全分离这两个类。

当我在一个类中有一个静态集合,其中包含类的实例和一些静态方法来管理集合时,这种情况经常发生。一旦你思考一下,很明显你的类不是在做“一件事”,它是一个集合,做一些完全不同的事情。

现在,让我们稍微重构一下这个问题:如果你把你的类分成一个类,其中所有的东西都是静态的,而另一个类只是一个“普通类”,然后忘记“普通类”,那么你的问题就变成了纯静态类vs单例,这是在这里详细讨论的(可能还有其他十几个问题)。

在我看来,这与性能无关,而是与设计有关。我不认为使用静态方法和使用静态变量是错误的(但我猜你实际上是在谈论方法调用)。

它只是关于如何分离逻辑并给它一个好的位置。有时这证明使用静态方法是正确的,java.lang.Math就是一个很好的例子。我认为,当您将大多数类命名为XxxUtil或Xxxhelper时,您最好重新考虑您的设计。