我见过这样的例子:

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

假设我可以有一个Constants类来包装常量,并将它们声明为静态final。我几乎不知道Java,我想知道这是否是创建常量的最佳方式。


当前回答

一个好的面向对象设计不应该需要很多公开可用的常量。大多数常量都应该封装在需要它们完成工作的类中。

其他回答

在单独的类中创建静态final常量可能会给您带来麻烦。Java编译器实际上会对此进行优化,并将常量的实际值放置到引用它的任何类中。

如果你稍后更改了Constants类,并且没有对引用该类的其他类进行严格的重新编译,那么你最终将使用新旧值的组合。

不要把它们看作常量,而应该把它们看作配置参数,并创建一个类来管理它们。让值是非final的,甚至可以考虑使用getter。将来,当您确定其中一些参数实际上应该由用户或管理员进行配置时,这将变得容易得多。

仅仅为了保存常量而使用接口是一种糟糕的做法(Josh Bloch将其命名为常量接口模式)。以下是乔希的建议:

如果常数与 现有的类或接口 是否应该将它们添加到类中 接口。例如,所有的 盒装的数字基元类, 如Integer和Double,导出 MIN_VALUE和MAX_VALUE常量。如果 这些常数最好看成 枚举类型的成员 应该用enum导出它们吗 类型。否则,您应该导出 带有不可实例化对象的常量 实用程序类。

例子:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

关于命名约定:

按照惯例,这些字段有名称 由大写字母组成的 用下划线分隔的单词。它是 重要的是,这些字段包含 要么是原始值,要么是引用 到不可变对象。

我使用以下方法:

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

例如,我使用Constants.DB.Connection.URL来获取常量。 对我来说,它看起来更“面向对象”。

有一定的观点来回答这个问题。首先,java中的常量通常被声明为public、static和final。原因如下:

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

我永远不会为CONSTANTS访问器/对象使用接口,因为接口通常是需要实现的。这看起来是不是很有趣:

String myConstant = IMyInterface.CONSTANTX;

相反,我会在一些不同的方法中进行选择,基于一些小的权衡,所以这取决于你需要什么:

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe

我同意使用界面不是正确的方法。在Bloch的《Effective Java》中,避免这种模式甚至有自己的项目(#18)。

Bloch反对常量接口模式的一个论点是,常量的使用是一个实现细节,但是实现一个使用它们的接口会在导出的API中暴露该实现细节。

public|private static final TYPE NAME = VALUE;模式是一种声明常数的好方法。就我个人而言,我认为最好避免创建一个单独的类来存放所有的常量,但除了个人偏好和风格之外,我还没有看到不这样做的理由。

如果常量可以很好地建模为枚举,请考虑1.5或更高版本中可用的枚举结构。

如果您使用的是1.5以前的版本,您仍然可以通过使用普通的Java类来实现类型安全枚举。(详见这个网站)。