你如何在Java中定义一个常量类?
假设你需要定义一个类,它只保存常量。
public static final String SOME_CONST = "SOME_VALUE";
这样做的首选方法是什么?
- 接口
- 抽象类
- 最后一堂课
我应该使用哪一个,为什么?
澄清一些答案:
枚举 – 我不打算使用枚举,我没有枚举任何东西,只是收集一些不相关的常量。
接口 – 我不打算将任何类设置为实现接口的类。 只是想使用接口来调用常量,如: 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.把它们放在包含最常用的逻辑的类中
…抱歉,无法抗拒;-)
-
私有构造函数的一个缺点是方法的存在永远不能被testing。
-
由自然概念的Enum很好地适用于特定的领域types,将其应用于分散常量看起来不够好
枚举的概念是“枚举是一组密切相关的项目”。
-
扩展/实现一个常量接口是一个不好的习惯,很难考虑扩展一个不可变常量的需求,而不是直接引用它。
-
如果应用像SonarSource这样的质量工具,有规则迫使开发者放弃不断的接口,这是一个尴尬的事情,因为许多项目享受不断的接口,很less看到“扩展”的事情发生在常量接口