什么时候不要在 Java 中使用 static 关键字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1766715/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When NOT to use the static keyword in Java?
提问by
When is it considered poor practice to use the static keyword in Java on method signatures? If a method performs a function based upon some arguments, and does not require access to fields that are not static, then wouldn't you always want these types of methods to be static?
什么时候在 Java 中对方法签名使用 static 关键字被认为是不好的做法?如果一个方法基于某些参数执行一个函数,并且不需要访问非静态字段,那么您是否总是希望这些类型的方法是静态的?
采纳答案by Jon Skeet
One reason why you maynot want it to be static is to allow it to be overridden in a subclass. In other words, the behaviour may not depend on the data within the object, but on the exact type of the object. For example, you might have a general collection type, with an isReadOnly
property which would return false
in always-mutable collections, true
in always-immutable collections, and depend on instance variables in others.
您可能不希望它是静态的一个原因是允许它在子类中被覆盖。换句话说,行为可能不取决于对象内的数据,而是取决于对象的确切类型。例如,您可能有一个通用集合类型,其isReadOnly
属性将false
在始终可变的集合中返回,true
在始终不可变的集合中返回,并依赖于其他实例变量。
However, this is quite rare in my experience - and should usually be explicitly specified for clarity. Normally I'd make a method which doesn't depend on any object state static.
但是,根据我的经验,这种情况很少见 - 通常应该明确指定以保持清晰。通常我会创建一个不依赖于任何静态对象状态的方法。
回答by Eric Petroelje
What you say is sort of true, but what happens when you want to override the behavior of that method in a derived class? If it's static, you can't do that.
你说的有点对,但是当你想在派生类中覆盖该方法的行为时会发生什么?如果它是静态的,你就不能这样做。
As an example, consider the following DAO type class:
例如,考虑以下 DAO 类型类:
class CustomerDAO {
public void CreateCustomer( Connection dbConn, Customer c ) {
// Some implementation, created a prepared statement, inserts the customer record.
}
public Customer GetCustomerByID( Connection dbConn, int customerId ) {
// Implementation
}
}
Now, none of those methods require any "state". Everything they need is passed as parameters. So they COULD easily be static. Now the requirement comes along that you need to support a different database (lets say Oracle)
现在,这些方法都不需要任何“状态”。他们需要的一切都作为参数传递。所以它们很容易是静态的。现在需要支持不同的数据库(比如 Oracle)
Since those methods are not static, you could just create a new DAO class:
由于这些方法不是静态的,您可以创建一个新的 DAO 类:
class OracleCustomerDAO : CustomerDAO {
public void CreateCustomer( Connection dbConn, Customer c ) {
// Oracle specific implementation here.
}
public Customer GetCustomerByID( Connection dbConn, int customerId ) {
// Oracle specific implementation here.
}
}
This new class could now be used in place of the old one. If you are using dependancy injection, it might not even require a code change at all.
现在可以使用这个新类来代替旧类。如果您使用依赖注入,它甚至可能根本不需要更改代码。
But if we had made those methods static, that would make things much more complicated as we can't simply override the static methods in a new class.
但是,如果我们将这些方法设为静态,那会使事情变得更加复杂,因为我们不能简单地在新类中覆盖静态方法。
回答by Jonathan Feinberg
That's right. Indeed, you have to contort what might otherwise be a reasonable design (to have some functions not associated with a class) into Java terms. That's why you see catch-all classes such as FredsSwingUtils and YetAnotherIOUtils.
这是正确的。实际上,您必须将原本可能是合理的设计(使某些函数与类无关)扭曲为 Java 术语。这就是为什么您会看到诸如 FredsSwingUtils 和 YetAnotherIOUtils 之类的全能类。
回答by Pascal Thivent
In general, I prefer instance methods for the following reasons:
一般来说,我更喜欢实例方法,原因如下:
- static methods make testing hard because they can't be replaced,
- static methods are more procedural oriented.
- 静态方法使测试变得困难,因为它们无法替代,
- 静态方法更面向过程。
In my opinion, static methods are OK for utility classes (like StringUtils
) but I prefer to avoid using them as much as possible.
在我看来,静态方法适用于实用程序类(如StringUtils
),但我更愿意尽可能避免使用它们。
回答by Gnark
when you want to use a class member independently of any object of that class,it should be declared static.
If it is declared static it can be accessed without an existing instance of an object of the class.
A static member is shared by all objects of that specific class.
当你想独立于该类的任何对象使用一个类成员时,它应该被声明为静态的。
如果它被声明为静态,则可以在没有该类对象的现有实例的情况下访问它。静态成员由该特定类的所有对象共享。
回答by Kevin Bourrillion
Two of the greatest evils you will ever encounter in large-scale Java applications are
在大型 Java 应用程序中您将遇到的两个最大的弊端是
- Static methods, except those that are pure functions*
- Mutable static fields
- 静态方法,纯函数除外*
- 可变静态字段
These ruin the modularity, extensibility and testability of your code to a degree that I realize I cannot possibly hope to convince you of in this limited time and space.
这些破坏了代码的模块化、可扩展性和可测试性,我意识到我不可能希望在有限的时间和空间内说服你。
*A "pure function" is any method which does not modify any state and whose result depends on nothing but the parameters provided to it. So, for example, any function that performs I/O (directly or indirectly) is not a pure function, but Math.sqrt(), of course, is.
*“纯函数”是不修改任何状态且其结果仅取决于提供给它的参数的任何方法。因此,例如,任何执行 I/O(直接或间接)的函数都不是纯函数,但 Math.sqrt() 当然是。
More blahblah about pure functions(self-link) and why you want to stick to them.
更多关于纯函数(自链接)以及为什么要坚持使用它们的废话。
I strongly encourage you to favor the "dependency injection" style of programming, possibly supported by a framework such as Spring or Guice (disclaimer: I am co-author of the latter). If you do this right, you will essentially neverneed mutable static state or non-pure static methods.
我强烈鼓励您支持“依赖注入”编程风格,可能由 Spring 或 Guice 等框架支持(免责声明:我是后者的合著者)。如果你做对了,你基本上永远不需要可变静态或非纯静态方法。
回答by Roboprog
An additional annoyance about static methods: there is no easy way to pass a reference to such a function around without creating a wrapper class around it. E.g. - something like:
关于静态方法的另一个烦恼:没有简单的方法来传递对这样一个函数的引用而不在它周围创建一个包装类。例如 - 类似:
FunctorInterface f = new FunctorInterface() { public int calc( int x) { return MyClass.calc( x); } };
I hate this kind of java make-work. Maybe a later version of java will get delegates or a similar function pointer / procedural type mechanism?
我讨厌这种java make-work。也许更高版本的java会获得委托或类似的函数指针/过程类型机制?
A minor gripe, but one more thing to notlike about gratuitous static functions, er, methods.
一个小小的抱怨,但还有一件事不喜欢免费的静态函数,呃,方法。
回答by toluju
Static methods are usually written for two purposes. The first purpose is to have some sort of global utility method, similar to the sort of functionality found in java.util.Collections. These static methods are generally harmless. The second purpose is to control object instantiation and limit access to resources (such as database connections) via various design patterns such as singletonsand factories. These can, if poorly implemented, result in problems.
静态方法通常有两个目的。第一个目的是拥有某种全局实用方法,类似于java.util.Collections 中的功能。这些静态方法通常是无害的。第二个目的是通过各种设计模式(例如单例和工厂)控制对象实例化并限制对资源(例如数据库连接)的访问。如果实施不当,这些可能会导致问题。
For me, there are two downsides to using static methods:
对我来说,使用静态方法有两个缺点:
- They make code less modular and harder to test / extend. Most answers already addressed this so I won't go into it any more.
- Static methods tend to result in some form of global state, which is frequently the cause of insidious bugs. This can occur in poorly written code that is written for the second purpose described above. Let me elaborate.
- 它们使代码不那么模块化并且更难测试/扩展。大多数答案已经解决了这个问题,所以我不再赘述。
- 静态方法往往会导致某种形式的全局状态,这通常是潜在错误的原因。这可能发生在为上述第二个目的编写的糟糕代码中。让我详细说明一下。
For example, consider a project that requires logging certain events to a database, and relies on the database connection for other state as well. Assume that normally, the database connection is initialized first, and then the logging framework is configured to write certain log events to the database. Now assume that the developers decide to move from a hand-written database framework to an existing database framework, such as hibernate.
例如,考虑一个需要将某些事件记录到数据库的项目,并且其他状态也依赖于数据库连接。假设正常情况下,首先初始化数据库连接,然后将日志框架配置为将某些日志事件写入数据库。现在假设开发人员决定从一个手写的数据库框架转移到一个现有的数据库框架,比如 hibernate。
However, this framework is likely to have its own logging configuration - and if it happens to be using the same logging framework as yours, then there is a good chance there will be various conflicts between the configurations. Suddenly, switching to a different database framework results in errors and failures in different parts of the system that are seemingly unrelated. The reason such failures can happen is because the logging configuration maintains global state accessed via static methods and variables, and various configuration properties can be overridden by different parts of the system.
然而,这个框架很可能有自己的日志配置——如果它碰巧使用与你相同的日志框架,那么配置之间很可能会出现各种冲突。突然间,切换到不同的数据库框架会导致系统不同部分出现看似无关的错误和故障。发生此类故障的原因是因为日志配置维护通过静态方法和变量访问的全局状态,并且系统的不同部分可以覆盖各种配置属性。
To get away from these problems, developers should avoid storing any state via static methods and variables. Instead, they should build clean APIs that let the users manage and isolate state as needed. BerkeleyDBis a good example here, encapsulating state via an Environmentobject instead of via static calls.
为了避免这些问题,开发人员应该避免通过静态方法和变量存储任何状态。相反,他们应该构建干净的 API,让用户根据需要管理和隔离状态。BerkeleyDB就是一个很好的例子,它通过Environment对象而不是静态调用来封装状态。
回答by Subramanian
Two questions here 1) A static method that creates objects stays loaded in memory when it is accessed the first time? Isnt this (remaining loaded in memory) a drawback? 2) One of the advantages of using Java is its garbage collection feature - arent we ignoring this when we use static methods?
这里有两个问题 1) 创建对象的静态方法在第一次访问时会保持加载在内存中吗?这不是(仍然加载在内存中)一个缺点吗?2) 使用 Java 的优势之一是它的垃圾收集功能——当我们使用静态方法时,我们不会忽略这一点吗?