为什么静态variables被视为邪恶?
我是一个Java程序员,他是企业界的新手。 最近我开发了一个使用Groovy和Java的应用程序。 所有通过我写的代码使用了相当多的静态。 我被高级技术人员要求削减所使用的静态数量。 我google了一下,我发现很多程序员都反对使用静态variables。
我发现使用更方便的静态variables。 而且我认为它们也是有效的(请纠正我,如果我错了),因为如果我不得不对一个类中的函数进行10,000次调用,我会很高兴使该方法静态,并使用一个简单的Class.methodCall()
而不是使用10,000个实例的类来混淆内存,对吧?
而且,静态减less了代码其他部分之间的相互依赖关系。 他们可以作为完美的国家持有者。 除此之外,我发现静态在Smalltalk和Scala等语言中得到了广泛的应用。 那么为什么对程序员(尤其是Java领域)的静态压制呢?
PS:如果我对静力学的假设是错误的,请纠正我。
静态variables代表全局状态。 这很难推理和难以testing:如果我创build一个对象的新实例,我可以在testing中推测它的新状态。 如果我使用使用静态variables的代码,它可能处于任何状态 – 任何事情都可能正在修改它。
我可以继续相当长的一段时间,但要想到的更大的概念是,事物的范围越紧密,就越容易推理。 我们善于思考小事情,但是如果没有模块化,就很难推断一百万行系统的状态。 这适用于各种各样的东西,顺便说一句 – 不只是静态variables。
它不是非常面向对象:静态可能被某些人认为是“恶”的一个原因是它们违背了面向对象的范式 。 特别是违反了数据封装在对象(可以扩展,隐藏信息等)的原则。 静态方法,就像你所描述的那样,基本上是把它们作为一个全局variables来避免处理像范围这样的问题。 然而,全局variables是过程式或命令式编程范式的决定性特征之一,而不是“良好的”面向对象的代码的特征。 这并不是说程序模式是不好的,但是我得到的印象是你的主pipe期望你写“好的面向对象的代码”,而你真的想写“好的程序代码”。
Java中有许多变种,当你开始使用并不总是显而易见的静态。 例如,如果你有两个程序在同一个虚拟机上运行,那么他们会把这个静态variables的值删掉,并且弄乱对方的状态? 或者当你扩展类时会发生什么,你可以覆盖静态成员? 你的虚拟机是否内存不足,因为你的虚拟机的数量是疯狂的,并且内存不能被其他需要的实例对象回收?
对象生命周期:另外,静态的生命周期与程序的整个运行时间相匹配。 这意味着,即使一旦你完成了使用你的类,所有这些静态variables的内存不能被垃圾收集。 例如,如果你的variables是非静态的,在你的main()函数中你创build了一个你的类的实例,然后要求你的类执行一个特定的函数10000次,一旦这10000次调用完成,并且你删除了对单个实例的引用,所有的静态variables都可以被垃圾收集和重用。
防止某些重用:另外,静态方法不能用来实现一个接口,所以静态方法可以防止某些面向对象的特性的使用。
其他选项:如果效率是您最关心的问题,那么可能还有其他更好的方法来解决速度问题,而不是只考虑调用通常比创build更快的优势。 考虑是否需要瞬态或挥发性修饰符。 为了保持被内联的能力,一个方法可以被标记为final而不是静态的。 方法参数和其他variables可以被标记为最终的,以允许某些编译器优化基于关于什么可以改变这些variables的假设。 一个实例对象可以重复使用多次,而不是每次都创build一个新的实例。 一般来说,可能会有应用程序开启优化开关。 也许,应该devise这样的devise,以便10,000次运行可以是multithreading的并且利用多处理器内核。 如果可移植性不是问题,那么也许本地方法会比静态方法更快地获得速度。
如果由于某种原因你不想要一个对象的多个副本, singletondevise模式比静态对象有优势,比如线程安全(假设你的singleton被编码得很好),允许延迟初始化,保证对象已经正确当它被使用时被初始化,子类,testing和重构代码的优点,更不用说,如果在某些时候你改变主意只想要一个对象的实例,移除代码以防止重复实例比重构所有的静态variables代码来使用实例variables更重要。 我之前必须这样做,它并不好玩,最终你不得不编辑更多的课程,这会增加你引入新bug的风险……第一次设置“正确”即使它看起来有缺点。 对于我来说,如果你决定下一步的工作,你需要重新工作,多次复制可能是最不经常使用静态的最有说服力的理由之一。 因此,我也不同意你的陈述,静态减less相互依赖关系,如果你有很多可以直接访问的静态信息,而不是一个“知道怎么做”的对象,东西“本身。
邪恶是一个主观的术语。
您不会在创build和销毁方面控制静态。 他们生活在程序装载和卸载的要求。
由于静态存在于一个空间中,所有希望使用它们的线程都必须经过必须pipe理的访问控制。 这意味着计划更加耦合,这种变化更难以设想和pipe理(就像J Skeet所说的)。 这导致孤立变化影响的问题,从而影响如何pipe理testing。
这是我与他们的两个主要问题。
不。全球国家本身并不是邪恶的。 但是,我们必须看你的代码,看看你是否正确使用它。 新手滥用全球状态是很有可能的。 就像他会滥用每一种语言function一样。
全球国家是绝对必要的。 我们无法避免全球国家。 我们不能避免推论全球国家。 – 如果我们关心理解我们的应用语义。
那些试图摆脱全球国家的人不可避免地以一个更复杂的体系结束 – 而全球的国家仍然存在,在许多层层的指导下巧妙地/白痴地伪装起来; 在解开所有的指示之后,我们仍然必须对全球国家进行推理。
就像spring那些用xml大声宣布全球状态的人一样,认为它是优越的。
@Jon Skeet if I create a new instance of an object
现在有两件事情可以推论 – 对象中的状态以及托pipe对象的环境的状态。
静态variables有两个主要问题:
- 线程安全 – 根据定义,静态资源不是线程安全的
- 代码隐含 – 你不知道什么时候静态variables被实例化,是否会在另一个静态variables之前被实例化
如果您使用的不是“最终”关键字的“静态”关键字,这应该是仔细考虑您的devise的信号。 即使是“最终”的存在也不是一个自由通行证,因为一个可变的静态最终对象可能同样危险。
我估计有85%的时间我看到一个没有“最终”的“静态”,这是错误的。 通常,我会发现奇怪的解决方法来掩盖或隐藏这些问题。
请不要创build静态可变。 尤其是集合。 通常情况下,Collections应该在包含对象被初始化的时候被初始化,并且应该被devise成当被包含的对象被遗忘时被重置或者忘记。
使用静力学可能会产生非常微妙的错误,这将导致持续的工程师痛苦的日子。 我知道,因为我已经创造和追捕这些错误。
如果您想了解更多详情,请阅读…
为什么不使用静态?
静态方面有很多问题,包括编写和执行testing,以及不明显的细微错误。
依赖于静态对象的代码不容易被unit testing,并且静态不能被轻易地模拟(通常)。
如果使用静态方法,则不能将该类的实现交换出来,以便testing更高级别的组件。 例如,设想一个静态的CustomerDAO,它返回从数据库中加载的Customer对象。 现在我有一个类CustomerFilter,需要访问一些客户对象。 如果CustomerDAO是静态的,我不能在不初始化数据库并填充有用信息的情况下为CustomerFilter编写一个testing。
而数据库填充和初始化需要很长时间。 根据我的经验,您的数据库初始化框架会随着时间而改变,这意味着数据将会变形,testing可能会中断。 IE浏览器,想象客户1曾经是一个VIP,但数据库初始化框架已经改变,现在客户1不再是VIP,但您的testing是硬编码加载客户1 …
更好的方法是实例化CustomerDAO,并在构build时将其传递给CustomerFilter。 (更好的方法是使用Spring或其他控制反转框架。
一旦你这样做了,你可以在你的CustomerFilterTest中快速地模拟或者删除一个备用的DAO,这样你就可以对testing有更多的控制,
没有静态的DAO,testing会更快(没有数据库初始化),更可靠(因为在db初始化代码改变时它不会失败)。 例如,在这种情况下,就testing而言,确保客户1始终是一个VIP。
执行testing
统一运行unit testing套件(例如,使用Continuous Integration服务器)时,统计信息会造成实际问题。 想象一下networking套接字对象的静态映射,从一个testing保持打开状态。 第一个testing可能会在8080端口上打开一个Socket,但是当testing被拆除时,您忘了清除地图。 现在,当第二个testing启动时,它可能会在尝试为端口8080创build一个新的套接字时崩溃,因为端口仍然被占用。 想象一下,静态集合中的套接字引用不会被删除,(除了WeakHashMap)永远不会被垃圾收集,导致内存泄漏。
这是一个过于广泛的例子,但在大型系统中,这个问题一直发生。 人们不会想到unit testing在同一个JVM中反复地启动和停止它们的软件,但是它是对您的软件devise的一个很好的testing,如果您有追求高可用性的愿望,那么您需要注意这一点。
这些问题通常出现在框架对象中,例如,数据库访问,caching,消息传递和日志logging层。 如果您正在使用Java EE或一些最好的框架,他们可能为您pipe理了很多这样的工作,但是如果像我一样处理遗留系统,您可能会有很多定制框架来访问这些层。
如果适用于这些框架组件的系统configuration在unit testing之间发生变化,并且unit testing框架没有拆除并重build组件,则这些更改无法生效,并且当testing依赖于这些更改时,它们将失败。
即使是非框架组件也会遇到这个问题。 想象一下名为OpenOrders的静态地图。 你写一个testing,创build一些开放的订单,并检查以确保它们都处于正确的状态,然后testing结束。 另一个开发人员编写第二个testing,将所需的订单放入OpenOrders地图,然后声明订单的数量是准确的。 单独运行,这些testing都会通过,但是当在一个套件中一起运行时,它们将会失败。
更糟的是,失败可能是基于testing运行的顺序。
在这种情况下,通过避免静态,可以避免在testing实例间持续数据的风险,确保更好的testing可靠性。
微妙的错误
如果您在高可用性环境中工作,或者在线程可能启动和停止的任何地方工作,那么当您的代码在生产环境中运行时,上面提到的与unit testing套件相同的问题也可以应用。
在处理线程时,而不是使用静态对象来存储数据,最好使用在线程启动阶段初始化的对象。 这样,每次启动线程时,都会创build对象的新实例(具有潜在的新configuration),并避免线程的一个实例中的数据stream向下一个实例。
当线程死亡时,静态对象不会被重置或垃圾收集。 想象一下,你有一个叫做“EmailCustomers”的线程,当它启动的时候,它会填充一个静态的String集合和一个电子邮件地址列表,然后开始给每个地址发邮件。 比方说,线程被中断或取消,所以你的高可用性框架重新启动线程。 然后当线程启动时,它重新加载客户列表。 但是,由于收集是静态的,因此可能会保留之前收集的电子邮件地址列表。 现在有些客户可能会收到重复的电子邮件
旁白:静态决赛
尽pipe存在技术实现差异,但是“静态最终”的使用实际上是C#定义的Java等价物。 AC / C ++ #define在编译之前由预处理器交换出代码。 一个Java“静态最终”将结束驻留在堆栈上的内存。 这样,它就更像C ++中的“static const”variables,而不是#define。
概要
我希望这有助于解释为什么静力学有问题的几个基本原因。 如果您正在使用Java EE或Spring等现代Java框架,则可能不会遇到这些情况中的很多情况,但是如果您正在处理大量遗留代码,则可能会变得更加频繁。
由于没有人提到它: 并发性。 如果你有多个线程读写静态variables,静态variables会让你感到惊讶。 这在networking应用程序(例如ASP.NET)中很常见,并且会导致一些相当疯狂的错误。 例如,如果您有一个由页面更新的静态variables,并且页面是由两个人几乎同时请求的,则一个用户可能会得到其他用户期望的结果,或者更糟糕。
静态减less了代码其他部分之间的相互依赖关系。 他们可以作为完美的国家持有者
我希望你准备好使用locking和处理争用。
*其实Preet Sangha提到了它。
如果我不得不对一个类中的函数进行10,000次调用,我会很高兴使这个方法成为静态的,并且使用一个简单的class.methodCall()而不是使用该类的10,000个实例来混淆内存。
您必须平衡将数据封装到具有状态的对象中的需求,而不是简单地计算某些数据上的函数的结果。
而且,静态减less了代码其他部分之间的相互依赖关系。
封装也是如此。 在大型应用程序中,静态代码倾向于生成意大利面代码,不容易重构或testing。
其他答案也提供了很好的理由,防止过度使用静态。
静态variables通常被认为是不好的,因为它们代表了全局状态,因此更难推理。 特别是,它们打破了面向对象编程的假设。 在面向对象编程中,每个对象都有自己的状态,由实例(非静态)variables表示。 静态variables表示跨实例的状态,可能更难以进行unit testing。 这主要是因为将更改静态variables隔离到单个testing更加困难。
也就是说,区分常规静态variables(通常被认为是不好的)和最终的静态variables(AKA常量;不是那么糟糕)是很重要的。
在我看来,它几乎不涉及性能,而是关于devise。 我不认为静态方法的使用是由于静态variables的使用(但是我想你实际上正在谈论方法调用)。
这只是关于如何分离逻辑和给它一个好地方。 有时候,使用静态方法certificatejava.lang.Math
是一个很好的例子。 我Xxxhelper
你给大部分的class级命名为XxxUtil
或Xxxhelper
你最好重新考虑一下你的devise。
有人可能会build议,在大多数情况下,你使用一个静态variables,你真的想要使用单例模式 。
全局状态的问题是,有时在简单的语境中有意义的是全局的,在实际的情况下需要更灵活一点,这就是单例模式变得有用的地方。
还有一个原因:脆弱。
如果你有一个class级,大多数人希望能够创build并随意使用它。
你可以certificate不是这种情况,或者防止它(单身/工厂模式) – 但这是额外的工作,因此是一个额外的成本。 即使这样,在一个大公司,有人会尝试在某个时候使用你的class级,而没有充分注意所有的好评或工厂。
如果你使用了很多静态variables,那将会中断。 错误是昂贵的。
性能提高了0.0001%,潜在无知的开发人员改变了鲁棒性,在很多情况下,鲁棒性是不错的select。
优点:
静态成员/方法在辅助类中使用,就像math或常量类一样。 这有助于其他对象使用string或有用的函数,您不需要创build对象但使用类名称调用。 示例 – 使用静态函数调用单例对象。
缺点:
静态成员是类的一部分,因此保留在内存中,直到应用程序终止,并且不能垃圾收集。 使用多余的静态成员有时会预测,你不能devise你的产品,并试图与静态/程序编程的警察。 它表示面向对象的devise受到了损害。 这可能导致内存溢出。 另外,如果你在Java中使任何静态方法成为一些缺点,例如你不能在Java中重载任何静态方法,那么你就不能用模拟来replace这个方法。 由于静态方法维护全局状态,因此可以在并发环境中创build难以检测和修复的细微错误。
要记住的事情:
静态variables将成为类定义的一部分,而不是在堆上。 但是,如果知道将从多个位置访问对象,则静态variables很有用。 访问静态资源不是线程安全的。 您可能会在线程环境中得到奇怪/不可预知的结果。 但是,如果你只读静态值,然后使用线程是好的。
如何静态破解封装:
它们的技术实现是允许在一个类的所有实例中维护状态。 问题是,这本质上不是面向对象,因为它无视封装。 如果一个variables可以被类的任何实例改变,那么封装/信息隐藏背后的基本原理就完全失去了:一个对象不再完全控制它的状态。 现在的状态依赖于本质上是全球性的variables。 我们知道这是不好的。 即使私有的静态variables在全球范围内维护状态,但仅限于访问。 对象的任何实例都可以改变导致歧义的静态variables,因为对象的单个实例不再控制自己的状态。 状态变化可以在不知道依赖于该状态的对象的情况下任意发生,这是有问题的,因为当这种情况发生时对象可能无法正常工作。 就像人们常说的,“inheritance破坏封装”一样,这样做更加严重:不仅暴露内部实现,还暴露内部状态。
总结在Java中使用静态方法的几个基本优点和缺点:
优点:
- 全局可访问,即不与任何特定对象实例绑定。
- 每个JVM一个实例。
- 可以通过使用类名来访问(不需要对象)。
- 包含适用于所有实例的单个值。
- 在JVM启动时加载并在JVMclosures时死亡。
- 他们不修改对象的状态。
缺点:
- 静态成员总是他们正在使用或不使用的记忆天气的一部分。
- 您无法控制静态variables的创build和销毁。 有用地,它们是在程序加载时创build的,并且在程序卸载时(或者JVMclosures时)被销毁。
- 您可以使用同步使静态线程安全,但是您需要一些额外的努力。
- 如果一个线程改变了一个静态variables的值,可能会破坏其他线程的function。
- 在使用之前,你必须知道“静态”。
- 你不能覆盖静态方法。
- 序列化不适合他们。
- 他们不参与运行时多态性。
- 如果使用大量的静态variables/方法,存在一个内存问题(在某种程度上,但我猜不太多)。 因为在程序结束之前他们不会成为GC。
- 静态方法也很难testing。
Static variables most importantly creates problem with security of data (any time changed,anyone can change,direct access without object, etc.)
For further info read this Thanks.
I find static variables more convenient to use. And I presume that they are efficient too (Please correct me if I am wrong) because if I had to make 10,000 calls to a function within a class, I would be glad to make the method static and use a straightforward class.methodCall() on it instead of cluttering the memory with 10,000 instances of the class, Right?
I see what you think, but a simple Singleton pattern will do the same without having to instantiate 10 000 objects.
static methods can be used, but only for functions that are related to the object domain and do not need or use internal properties of the object.
例如:
public class WaterContainer { private int size; private int brand; ...etc public static int convertToGallon(int liters)... public static int convertToLiters(int gallon)... }
The issue of 'Statics being evil' is more of an issue about global state. The appropriate time for a variable to be static, is if it does not ever have more than one state; IE tools that should be accessible by the entire framework and always return the same results for the same method calls are never 'evil' as statics. As to your comment:
I find static variables more convenient to use. And I presume that they are efficient too
Statics are the ideal and efficient choice for variables/classes that do not ever change .
The problem with global state is the inherent inconsistency that it can create. Documentation about unit tests often address this issue, since any time there is a global state that can be accessed by more than multiple unrelated objects, your unit tests will be incomplete, and not 'unit' grained. As mentioned in this article about global state and singletons , if object A and B are unrelated (as in one is not expressly given reference to another), then A should not be able to affect the state of B.
There are some exceptions to the ban global state in good code, such as the clock. Time is global, and–in some sense–it changes the state of objects without having a coded relationship.
Seems to me that you're asking about static variables but you also point out static methods in your examples.
Static variables are not evil – they have its adoption as global variables like constants in most cases combined with final modifier, but as it said don't overuse them.
Static methods aka utility method. It isn't generally a bad practice to use them but major concern is that they might obstruct testing.
As a example of great java project that use a lot of statics and do it right way please look at Play! framework . There is also discussion about it in SO.
Static variables/methods combined with static import are also widely used in libraries that facilitate declarative programming in java like: make it easy or Hamcrest . It wouldn't be possible without a lot of static variables and methods.
So static variables (and methods) are good but use them wisely!
My $.02 is that several of these answers are confusing the issue, rather than saying "statics are bad" I think its better to talk about scoping and instances.
What I would say is that a static is a "class" variables – it represenst a value that is shared across all instances of that class. Typically it should be scoped that way as well (protected or private to class and its instances).
If you plan to put class-level behavior around it and expose it to other code, then a singleton may be a better solution to support changes in the future (as @Jessica suggested). This is because you can use interfaces at the instance/singleton level in ways that you can not use at the class level – in particular inheritance.
Some thoughts on why I think some of the aspects in other answers are not core to the question…
Statics are not "global". In Java scoping is controlled separately from static/instance.
Concurrency is no less dangerous for statics than instance methods. It's still state that needs to be protected. Sure you may have 1000 instances with an instance variable each and only one static variable, but if the code accessing either isn't written in a thread-safe way you are still screwed – it just may take a little longer for you to realize it.
Managing life cycle is an interesting argument, but I think it's a less important one. I don't see why its any harder to manage a pair of class methods like init()/clear() than the creation and destroying of a singleton instance. In fact, some might say a singleton is a little more complicated due to GC.
PS, In terms of Smalltalk, many of its dialects do have class variables, but in Smalltalk classes are actually instances of Metaclass so they are really are variables on the Metaclass instance. Still, I would apply the same rule of thumb. If they are being used for shared state across instances then ok. If they are supporting public functionality you should look at a Singleton. Sigh, I sure do miss Smalltalk….
There's nothing wrong with static variables per se. It's just the Java syntax that's broken. Each Java class actually defines two structures- a singleton object which encapsulates static variables, and an instance. Defining both in the same source block is pure evil, and results in a code that's hard to read. Scala did that right.
I have just summarized some of the points made in the answers. If you find anything wrong please feel free to correct it.
Scaling: We have exactly one instance of a static variable per JVM. Suppose we are developing a library management system and we decided to put the name of book a static variable as there is only one per book. But if system grows and we are using multiple JVMs then we dont have a way to figure out which book we are dealing with?
Thread-Safety: Both instance variable and static variable need to be controlled when used in multi threaded environment. But in case of an instance variable it does not need protection unless it is explicitly shared between threads but in case of a static variable it is always shared by all the threads in the process.
Testing: Though testable design does not equal to good design but we will rarely observe a good design that is not testable. As static variables represent global state and it gets very difficult to test them.
Reasoning about state: If I create a new instance of a class then we can reason about the state of this instance but if it is having static variables then it could be in any state. 为什么? Because it is possible that the static variable has been modified by some different instance as static variable is shared across instances.
Serialization: Serialization also does not work well with them.
Creation and destruction: Creation and destruction of static variables can not be controlled. Usually they are created and destroyed at program loading and unloading time. It means they are bad for memory management and also add up the initialization time at start up.
But what if we really need them?
But sometimes we may have a genuine need of them. If we really feel the need of many static variables that are shared across the application then one option is to make use of Singleton Design pattern which will have all these variables. Or we can create some object which will have these static variable and can be passed around.
Also if the static variable is marked final it becomes a constant and value assigned to it once cannot be changed. It means it will save us from all the problems we face due to its mutability.
a) Reason about programs.
If you have a small- to midsize-program, where the static variable Global.foo is accessed, the call to it normally comes from nowhere – there is no path, and therefore no timeline, how the variable comes to the place, where it is used. Now how do I know who set it to its actual value? How do I know, what happens, if I modify it right now? I have grep over the whole source, to collect all accesses, to know, what is going on.
If you know how you use it, because you just wrote the code, the problem is invisible, but if you try to understand foreign code, you will understand.
b) Do you really only need one?
Static variables often prevent multiple programs of the same kind running in the same JVM with different values. You often don't foresee usages, where more than one instance of your program is useful, but if it evolves, or if it is useful for others, they might experience situations, where they would like to start more than one instance of your program.
Only more or less useless code which will not be used by many people over a longer time in an intensive way might go well with static variables.
There are two main questions in your post.
First, about static variables. Static variables are completelly unnecesary and it's use can be avoided easily. In OOP languajes in general, and in Java particularlly, function parameters are pased by reference, this is to say, if you pass an object to a funciont, you are passing a pointer to the object, so you dont need to define static variables since you can pass a pointer to the object to any scope that needs this information. Even if this implies that yo will fill your memory with pointers, this will not necesary represent a poor performance because actual memory pagging systems are optimized to handle with this, and they will maintain in memory the pages referenced by the pointers you passed to the new scope; usage of static variables may cause the system to load the memory page where they are stored when they need to be accessed (this will happen if the page has not been accesed in a long time). A good practice is to put all that static stuf together in some little "configuration clases", this will ensure the system puts it all in the same memory page.
Second, about static methods. Static methods are not so bad, but they can quickly reduce performance. For example, think about a method that compares two objects of a class and returns a value indicating which of the objects is bigger (tipical comparison method) this method can be static or not, but when invoking it the non static form will be more eficient since it will have to solve only two references (one for each object) face to the three references that will have to solve the static version of the same method (one for the class plus two, one for each object). But as I say, this is not so bad, if we take a look at the Math class, we can find a lot of math functions defined as static methods. This is really more eficient than putting all these methods in the class defining the numbers, because most of them are rarelly used and including all of them in the number class will cause the class to be very complex and consume a lot of resources unnecesarilly.
In concluson: Avoid the use of static variables and find the correct performance equilibrium when dealing with static or non static methods.
PS: Sorry for my english.
everything (can:) have its purpose, if you have bunch of threads that needs to share/cache data and also all accessible memory (so you dont split into contexts within one JVM) the static is best choice
-> of course you can force just one instance, but why?
i find some of the comments in this thread evil, not the statics 😉
All the answers above show why statics are bad. The reason they are evil is because it gives the false impression that you are writing object oriented code, when in fact you are not. That is just plain evil.
Static variables are not good nor evil. They represent attributes that describe the whole class and not a particular instance. If you need to have a counter for all the instances of a certain class, a static variable would be the right place to hold the value.
Problems appear when you try to use static variables for holding instance related values.
There are plenty of good answers here, adding to it,
Memory: Static variables are live as long as the class loader lives[in general till VM dies], but this is only in-case of bulk objects/references stored as static.
Modularization: consider concepts like IOC, dependencyInjection, proxy etc.. All are completely against tightly coupling/static implementations.
Other Con's: Thread Safety, Testability
Think that if you have an application with many users and you have define a static form, then every user will modify all other forms of other users too.
Static means global, whenever you mark a variable as static , you make it visible and shared between all instances of a class.
In multi-threaded environments, marking a variable as static would allow multiple threads to access and modify it concurrently and that's would leave it in inconsistent state and lead to several serious problems, the debugging of such problems is very harmful.
Although developers normally tend to protect their static variables from concurrent modifications using for example Synchronized blocks, it is a time-consuming task to always surround each modification with a Synchronized block and there's a high possibility that the developer forget to protect some modification code by mistake.
The common usage of static variables is for defining constants, try to diminish the usage of them as much as you can unless you have a very specific business case which couldn't be solved better without static variable ie when you define an auto generated ID field in a class.
For much details, check Static keyword in java
I think excessive uses of global variables with static keyword will also leads to memory leakage at some point of instance in the applica