102

假设您需要定义一个类,它所做的只是保存常量。

public static final String SOME_CONST = "SOME_VALUE";

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

  1. 界面
  2. 抽象类
  3. 最后一堂课

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


澄清一些答案:

枚举- 我不会使用枚举,我不会枚举任何东西,只是收集一些彼此不相关的常量。

接口- 我不会将任何类设置为实现接口的类。只想使用接口调用常量,如下所示:ISomeInterface.SOME_CONST.

4

11 回答 11

109

使用最终课程。为简单起见,您可以使用静态导入在另一个类中重用您的值

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

在另一个班级:

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}
于 2009-01-26T12:06:51.403 回答
39

您的澄清说明:“我不会使用枚举,我不会枚举任何东西,只是收集一些彼此不相关的常量。”

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

于 2009-01-26T12:28:20.377 回答
33

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

1)不要这样做。在与它们最相关的实际类中创建常量。拥有一个“常量包”类/接口并没有真正遵循 OO 最佳实践。

我和其他所有人时常忽略#1。如果您要这样做,那么:

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

3)界面这将起作用,但不是我的偏好,在#2 中可能会提到滥用。

一般来说,仅仅因为这些是常量并不意味着你不应该对它们应用正常的 oo 原则。如果只有一个类关心一个常量,那么它应该是私有的并且在那个类中。如果只有测试关心一​​个常量 - 它应该在测试类中,而不是生产代码中。如果在多个地方定义了一个常量(不仅仅是偶然地相同) - 重构以消除重复。等等 - 像对待方法一样对待它们。

于 2009-04-07T17:14:49.760 回答
14

正如 Joshua Bloch 在 Effective Java 中所说:

  • 接口只能用于定义类型,
  • 抽象类不会阻止实例化(它们可以被子类化,甚至建议它们被设计为子类化)。

如果所有常量都相关(如行星名称),则可以使用 Enum,将常量值放在与它们相关的类中(如果您可以访问它们),或者使用不可实例化的实用程序类(定义私有默认构造函数) .

class SomeConstants
{
    // Prevents instanciation of myself and my subclasses
    private SomeConstants() {}

    public final static String TOTO = "toto";
    public final static Integer TEN = 10;
    //...
}

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

于 2009-01-26T12:32:27.887 回答
7

我的首选方法是根本不这样做。当 Java 5 引入类型安全枚举时,常量的时代几乎消失了。甚至在此之前,乔什·布洛赫(Josh Bloch)发布了一个(稍微冗长的)版本,该版本适用于 Java 1.4(及更早版本)。

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

于 2009-01-26T12:06:59.653 回答
3

只需使用最终课程。

如果您希望能够添加其他值,请使用抽象类。

使用接口没有多大意义,接口应该指定合同。您只想声明一些常量值。

于 2009-01-26T12:03:23.017 回答
3

枚举不是这类东西的最佳选择吗?

于 2009-01-26T12:06:07.363 回答
3

enums很好。IIRC,有效Java(第2版)中的一项具有enum枚举标准选项的常量,这些选项interface为任何值实现[Java关键字]。

我的偏好是使用 [Java 关键字]interface而不是final classfor 常量。你隐含地得到public static final. 有些人会争辩说,ainterface允许糟糕的程序员实现它,但是无论你做什么,糟糕的程序员都会编写出糟糕的代码。

哪个更好看?

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.";
}
于 2009-01-26T13:47:29.547 回答
1

或者 4. 将它们放在包含使用常量的逻辑最多的类中

...对不起,无法抗拒;-)

于 2009-01-26T12:07:45.177 回答
0

对我来说最好的方法是enum

public enum SomeApiConstants {;

    public static final String SOME_CONST = "SOME_VALUE";

    //may be in hierarchy
    public enum ApiMapping {;
        public static final String VERSION = "/version";
        public static final String VERSION_LIST = "/list/{type}";
    }
}

优点:

  • 干净的代码
  • 不需要定义私有构造函数
  • 尝试实例化在编译时验证为java: enum types may not be instantiated
  • 防止克隆和反序列化
于 2021-07-09T08:03:14.647 回答
-1
  1. 私有构造函数的缺点之一是方法的存在永远无法测试。

  2. 枚举的性质概念很好地应用于特定的域类型,将其应用于分散的常量看起来不够好

Enum 的概念是“枚举是密切相关项的集合”。

  1. 扩展/实现常量接口是一种不好的做法,很难考虑扩展不可变常量而不是直接引用它的要求。

  2. 如果使用像 SonarSource 这样的质量工具,有规则迫使开发人员放弃常量接口,这是一件尴尬的事情,因为很多项目都喜欢常量接口,很少看到“扩展”的事情发生在常量接口上

于 2015-09-11T06:34:42.077 回答