你如何在Java中定义一个常量类?

假设你需要定义一个类,它只保存常量。

public static final String SOME_CONST = "SOME_VALUE"; 

这样做的首选方法是什么?

  1. 接口
  2. 抽象类
  3. 最后一堂课

我应该使用哪一个,为什么?


澄清一些答案:

枚举 – 我不打算使用枚举,我没有枚举任何东西,只是收集一些不相关的常量。

接口 – 我不打算将任何类设置为实现接口的类。 只是想使用接口来调用常量,如: ISomeInterface.SOME_CONST

使用最后一堂课。 为了简单起见,您可以使用静态导入来重新使用另一个类中的值

 public final class MyValues { public static final String VALUE1 = "foo"; public static final String VALUE2 = "bar"; } 

在另一个class级:

 import static MyValues.* //... if(variable.equals(VALUE1)){ //... } 

你的澄清指出:“我不打算使用枚举,我没有列举任何东西,只是收集一些常数,而这些常量之间没有任何关系。

如果这些常数根本不相关,为什么要一起收集呢? 将每个常量放在与其最密切相关的类中。

我的build议(按优先顺序递减):

1) 不要这样做 。 在最相关的实际类中创build常量。 拥有一大堆常量的类/接口并不是真正遵循面向对象的最佳实践。

我和其他人不时忽视#1。 如果你打算这样做:

2) 带有私有构造函数的最终类这至less可以防止任何人滥用你的“常量包”,通过扩展/实现它来轻松访问常量。 (我知道你说过你不会这样做 – 但是这并不意味着有人在你之后不会来)

3) 界面这将工作,但不是我的偏好给予#2可能的滥用提及。

一般来说,只是因为这些常数并不意味着你不应该把普通的原则应用于它们。 如果没有人在class级上关心一个常数 – 那么这个class级应该是私人的。 如果只有testing关心一​​个常数 – 它应该在testing类,而不是生产代码。 如果一个常量被定义在多个地方(不只是偶然相同) – 重构,以消除重复。 等 – 像你一样对待他们的方法。

正如Joshua Bloch在Effective Java中所指出的那样:

  • 接口只能用来定义types,
  • 抽象类不能阻止不稳定性(它们可以被分类,甚至build议它们被devise成子类)。

你可以使用一个枚举,如果所有的常量都是相关的(比如星球名称),把常量值放在它们相关的类中(如果你有权访问它们),或者使用非实例类(定义一个私有的默认构造函数) 。

 class SomeConstants { // Prevents instanciation of myself and my subclasses private SomeConstants() {} public final static String TOTO = "toto"; public final static Integer TEN = 10; //... } 

然后,如前所述,您可以使用静态导入来使用您的常量。

只用最后一堂课。

如果你想能够添加其他值使用抽象类。

使用接口没什么意义,接口应该指定一个合约。 你只是想声明一些常量值。

我最喜欢的方法是不要那样做。 当Java 5引入types安全枚举时,常量的年龄几乎死亡。 甚至在此之前,Josh Bloch发表了一个稍微罗嗦的版本,这个版本在Java 1.4(和更早的版本)上工作。

除非你需要与一些遗留代码的互操作性,否则真的没有理由再使用命名的string/整数常量。

enum是好的。 IIRC,有效Java(第二版)中的一个项目enum常量枚举实现任何值的[Java关键字] interface标准选项。

我的首选是在常量的final class上使用[Java关键字] interface 。 你隐式地得到public static final 。 有些人会争辩说,一个interface允许不好的程序员来实现它,但不好的程序员会写代码,不pipe你做什么,

哪个更好看?

 public final class SomeStuff { private SomeStuff() { throw new Error(); } public static final String SOME_CONST = "Some value or another, I don't know."; } 

要么:

 public interface SomeStuff { String SOME_CONST = "Some value or another, I don't know."; } 

这不是枚举最好的select吗?

或者4.把它们放在包含最常用的逻辑的类中

…抱歉,无法抗拒;-)

  1. 私有构造函数的一个缺点是方法的存在永远不能被testing。

  2. 由自然概念的Enum很好地适用于特定的领域types,将其应用于分散常量看起来不够好

枚举的概念是“枚举是一组密切相关的项目”。

  1. 扩展/实现一个常量接口是一个不好的习惯,很难考虑扩展一个不可变常量的需求,而不是直接引用它。

  2. 如果应用像SonarSource这样的质量工具,有规则迫使开发者放弃不断的接口,这是一个尴尬的事情,因为许多项目享受不断的接口,很less看到“扩展”的事情发生在常量接口