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

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

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

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


当前回答

a)关于程序的原因。

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

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

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

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

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

其他回答

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

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

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

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

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

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

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

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

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

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

总结在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.

我认为过度使用全局变量和静态关键字也会导致应用程序中实例的某些点的内存泄漏

我发现静态变量使用起来更方便。而且我认为它们也很有效(如果我错了请纠正我),因为如果我必须在一个类中对一个函数进行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)...

}

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

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