什么时候不在Java中使用static关键字?

时间:2022-09-04 10:59:55

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关键字被认为是不好的做法?如果方法基于某些参数执行函数,并且不需要访问非静态的字段,那么您是否总是希望这些类型的方法是静态的?

9 个解决方案

#1


31  

One reason why you may not 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属性在always-mutable集合中返回false,在always-immutable集合中返回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.

但是,根据我的经验,这种情况非常罕见 - 通常应明确说明。通常我会创建一个不依赖于任何对象状态静态的方法。

#2


42  

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.

关于纯粹功能(自我链接)的更多blahblah以及为什么要坚持它们。

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 never need mutable static state or non-pure static methods.

我强烈建议您支持“依赖注入”编程风格,可能由Spring或Guice等框架支持(免责声明:我是后者的合着者)。如果你这样做,你基本上不需要可变的静态或非纯静态方法。

#3


23  

In general, I prefer instance methods for the following reasons:

一般来说,我更喜欢实例方法,原因如下:

  1. static methods make testing hard because they can't be replaced,
  2. 静态方法使测试变得困难,因为它们无法替换,

  3. static methods are more procedural oriented.
  4. 静态方法更加面向程序。

In my opinion, static methods are OK for utility classes (like StringUtils) but I prefer to avoid using them as much as possible.

在我看来,静态方法对于实用程序类(如StringUtils)是可以的,但我更愿意尽量避免使用它们。

#4


4  

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.

但是如果我们将这些方法设置为静态,那将使事情变得更加复杂,因为我们不能简单地覆盖新类中的静态方法。

#5


1  

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 singletons and factories. These can, if poorly implemented, result in problems.

静态方法通常用于两个目的。第一个目的是使用某种全局实用方法,类似于java.util.Collections中的功能。这些静态方法通常是无害的。第二个目的是通过各种设计模式(如单例和工厂)来控制对象实例化并限制对资源(例如数据库连接)的访问。如果执行不当,这些可能会导致问题。

For me, there are two downsides to using static methods:

对我来说,使用静态方法有两个缺点:

  1. They make code less modular and harder to test / extend. Most answers already addressed this so I won't go into it any more.
  2. 它们使代码更少模块化,更难以测试/扩展。大多数答案已经解决了这个问题,所以我不再讨论了。

  3. 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.
  4. 静态方法往往会导致某种形式的全局状态,这通常是潜在的错误的原因。这可能发生在为上述第二个目的而编写的编写不良的代码中。让我详细说明一下。

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. BerkeleyDB is a good example here, encapsulating state via an Environment object instead of via static calls.

为了摆脱这些问题,开发人员应该避免通过静态方法和变量存储任何状态。相反,他们应该构建干净的API,让用户根据需要管理和隔离状态。 BerkeleyDB就是一个很好的例子,它通过Environment对象而不是静态调用来封装状态。

#6


0  

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这样的全能类。

#7


0  

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.

如果要独立于该类的任何对象使用类成员,则应将其声明为static。如果它被声明为static,则可以在没有该类对象的现有实例的情况下访问它。静态成员由该特定类的所有对象共享。

#8


0  

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 not like about gratuitous static functions, er, methods.

一个轻微的抱怨,但还有一件事不喜欢无偿的静态功能,呃,方法。

#9


0  

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的一个优点是它的垃圾收集功能 - 我们在使用静态方法时是否忽略了这一点?

#1


31  

One reason why you may not 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属性在always-mutable集合中返回false,在always-immutable集合中返回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.

但是,根据我的经验,这种情况非常罕见 - 通常应明确说明。通常我会创建一个不依赖于任何对象状态静态的方法。

#2


42  

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.

关于纯粹功能(自我链接)的更多blahblah以及为什么要坚持它们。

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 never need mutable static state or non-pure static methods.

我强烈建议您支持“依赖注入”编程风格,可能由Spring或Guice等框架支持(免责声明:我是后者的合着者)。如果你这样做,你基本上不需要可变的静态或非纯静态方法。

#3


23  

In general, I prefer instance methods for the following reasons:

一般来说,我更喜欢实例方法,原因如下:

  1. static methods make testing hard because they can't be replaced,
  2. 静态方法使测试变得困难,因为它们无法替换,

  3. static methods are more procedural oriented.
  4. 静态方法更加面向程序。

In my opinion, static methods are OK for utility classes (like StringUtils) but I prefer to avoid using them as much as possible.

在我看来,静态方法对于实用程序类(如StringUtils)是可以的,但我更愿意尽量避免使用它们。

#4


4  

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.

但是如果我们将这些方法设置为静态,那将使事情变得更加复杂,因为我们不能简单地覆盖新类中的静态方法。

#5


1  

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 singletons and factories. These can, if poorly implemented, result in problems.

静态方法通常用于两个目的。第一个目的是使用某种全局实用方法,类似于java.util.Collections中的功能。这些静态方法通常是无害的。第二个目的是通过各种设计模式(如单例和工厂)来控制对象实例化并限制对资源(例如数据库连接)的访问。如果执行不当,这些可能会导致问题。

For me, there are two downsides to using static methods:

对我来说,使用静态方法有两个缺点:

  1. They make code less modular and harder to test / extend. Most answers already addressed this so I won't go into it any more.
  2. 它们使代码更少模块化,更难以测试/扩展。大多数答案已经解决了这个问题,所以我不再讨论了。

  3. 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.
  4. 静态方法往往会导致某种形式的全局状态,这通常是潜在的错误的原因。这可能发生在为上述第二个目的而编写的编写不良的代码中。让我详细说明一下。

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. BerkeleyDB is a good example here, encapsulating state via an Environment object instead of via static calls.

为了摆脱这些问题,开发人员应该避免通过静态方法和变量存储任何状态。相反,他们应该构建干净的API,让用户根据需要管理和隔离状态。 BerkeleyDB就是一个很好的例子,它通过Environment对象而不是静态调用来封装状态。

#6


0  

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这样的全能类。

#7


0  

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.

如果要独立于该类的任何对象使用类成员,则应将其声明为static。如果它被声明为static,则可以在没有该类对象的现有实例的情况下访问它。静态成员由该特定类的所有对象共享。

#8


0  

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 not like about gratuitous static functions, er, methods.

一个轻微的抱怨,但还有一件事不喜欢无偿的静态功能,呃,方法。

#9


0  

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的一个优点是它的垃圾收集功能 - 我们在使用静态方法时是否忽略了这一点?