我见过这样的例子:

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

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


当前回答

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

其他回答

我强烈建议不要只使用一个常量类。这在当时看起来是一个好主意,但是当开发人员拒绝记录常量,并且类增长到包含500个以上彼此完全不相关的常量(与应用程序的完全不同方面相关)时,通常会导致常量文件完全不可读。而不是:

If you have access to Java 5+, use enums to define your specific constants for an application area. All parts of the application area should refer to enums, not constant values, for these constants. You may declare an enum similar to how you declare a class. Enums are perhaps the most (and, arguably, only) useful feature of Java 5+. If you have constants that are only valid to a particular class or one of its subclasses, declare them as either protected or public and place them on the top class in the hierarchy. This way, the subclasses can access these constant values (and if other classes access them via public, the constants aren't only valid to a particular class...which means that the external classes using this constant may be too tightly coupled to the class containing the constant) If you have an interface with behavior defined, but returned values or argument values should be particular, it is perfectly acceptible to define constants on that interface so that other implementors will have access to them. However, avoid creating an interface just to hold constants: it can become just as bad as a class created just to hold constants.

仅仅为了保存常量而使用接口是一种糟糕的做法(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;
}

关于命名约定:

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

我同意大多数人所说的,在处理常量集合时最好使用枚举。然而,如果你在Android上编程,有一个更好的解决方案:IntDef Annotation。

@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();

IntDef注释在一个简单的方面优于枚举,它占用的空间明显更少,因为它只是一个编译时标记。它不是一个类,也没有自动字符串转换属性。

我不会称这个类与常量相同(除了大小写)…我将至少有一类“设置”,或“值”,或“常量”,所有的常量都将存在。如果我有很多,我会将它们分组在逻辑常量类中(UserSettings, AppSettings等)。

根据上面的评论,我认为这是一个很好的方法,将老式的全局常量类(具有公共静态final变量)更改为类似枚举的等价物,如下所示:

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

这样我就可以把它们引用为:

Constants.StringConstant.DB_HOST