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

发布于 2024-07-12 04:15:36 字数 472 浏览 13 评论 0原文

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

public static final String SOME_CONST = "SOME_VALUE";

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

  1. Interface
  2. Abstract Class
  3. Final Class

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


Clarifications to some answers:

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

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

Suppose you need to define a class which all it does is hold constants.

public static final String SOME_CONST = "SOME_VALUE";

What is the preferred way of doing this?

  1. Interface
  2. Abstract Class
  3. Final Class

Which one should I use and why?


Clarifications to some answers:

Enums - I'm not going to use enums, I am not enumerating anything, just collecting some constants which are not related to each other in any way.

Interface - I'm not going to set any class as one that implements the interface. Just want to use the interface to call constants like so: ISomeInterface.SOME_CONST.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

涙—继续流 2024-07-19 04:15:36

使用最终类,并定义一个私有构造函数来隐藏公共构造函数。
为了简单起见,您可以使用静态导入在另一个类的另一个类中重用您的值

public final class MyValues {

  private MyValues() {
    // No need to instantiate the class, we can hide its constructor
  }

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

import static MyValues.*
//...

if (VALUE1.equals(variable)) {
  //...
}

Use a final class, and define a private constructor to hide the public one.
For simplicity you may then use a static import to reuse your values in another class

public final class MyValues {

  private MyValues() {
    // No need to instantiate the class, we can hide its constructor
  }

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

in another class :

import static MyValues.*
//...

if (VALUE1.equals(variable)) {
  //...
}
°如果伤别离去 2024-07-19 04:15:36

您的澄清指出:“我不会使用枚举,我不会枚举任何内容,只是收集一些彼此不以任何方式相关的常量。”

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

Your clarification states: "I'm not going to use enums, I am not enumerating anything, just collecting some constants which are not related to each other in any way."

If the constants aren't related to each other at all, why do you want to collect them together? Put each constant in the class which it's most closely related to.

欢烬 2024-07-19 04:15:36

我的建议(按偏好降序排列):

1)不要这样做。 在实际类中最相关的地方创建常量。 拥有“常量包”类/接口并没有真正遵循面向对象的最佳实践。

我和其他人都会时不时地忽略#1。 如果您打算这样做,那么:

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

3)界面这会起作用,但不是我的偏好,因为可能会出现滥用情况#2 中提到。

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

My suggestions (in decreasing order of preference):

1) Don't do it. Create the constants in the actual class where they are most relevant. Having a 'bag of constants' class/interface isn't really following OO best practices.

I, and everyone else, ignore #1 from time to time. If you're going to do that then:

2) final class with private constructor This will at least prevent anyone from abusing your 'bag of constants' by extending/implementing it to get easy access to the constants. (I know you said you wouldn't do this -- but that doesn't mean someone coming along after you won't)

3) interface This will work, but not my preference giving the possible abuse mention in #2.

In general, just because these are constants doesn't mean you shouldn't still apply normal oo principles to them. If no one but one class cares about a constant - it should be private and in that class. If only tests care about a constant - it should be in a test class, not production code. If a constant is defined in multiple places (not just accidentally the same) - refactor to eliminate duplication. And so on - treat them like you would a method.

梦初启 2024-07-19 04:15:36

正如 Joshua Bloch 在《Effective Java:

  • 接口应该仅用于定义类型》中指出的那样,
  • 抽象类不会阻止实例化(它们可以被子类化,甚至表明它们被设计为可子类化)。

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

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

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

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

As Joshua Bloch notes in Effective Java:

  • Interfaces should only be used to define types,
  • abstract classes don't prevent instanciability (they can be subclassed, and even suggest that they are designed to be subclassed).

You can use an Enum if all your constants are related (like planet names), put the constant values in classes they are related to (if you have access to them), or use a non instanciable utility class (define a private default constructor).

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

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

Then, as already stated, you can use static imports to use your constants.

末蓝 2024-07-19 04:15:36

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

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

My preferred method is not to do that at all. The age of constants pretty much died when Java 5 introduced typesafe enums. And even before then Josh Bloch published a (slightly more wordy) version of that, which worked on Java 1.4 (and earlier).

Unless you need interoperability with some legacy code there's really no reason to use named String/integer constants anymore.

许久 2024-07-19 04:15:36

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

我的偏好是使用 [Java 关键字]interface 而不是 final class 作为常量。 您隐式地获得了public static final。 有些人会认为接口允许糟糕的程序员实现它,但是无论你做什么,糟糕的程序员都会编写出糟糕的代码。

哪个看起来更好?

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.";
}

enums are fine. IIRC, one item in effective Java (2nd Ed) has enum constants enumerating standard options implementing a [Java keyword] interface for any value.

My preference is to use a [Java keyword] interface over a final class for constants. You implicitly get the public static final. Some people will argue that an interface allows bad programmers to implement it, but bad programmers are going to write code that sucks no matter what you do.

Which looks better?

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

Or:

public interface SomeStuff {
     String SOME_CONST = "Some value or another, I don't know.";
}
怎言笑 2024-07-19 04:15:36

枚举不是这些的最佳选择吗?各种各样的东西?

Aren't enums best choice for these kinds of stuff?

最丧也最甜 2024-07-19 04:15:36

对我来说最好的方法是enum

public enum SomeApiConstants {;
  // private constant 
  private static final String PREFIX = "/user";
  private static final String DT_FORMAT = "yyyyMMdd HH:mm:ss";

  // public constants
  public static final String SOME_CONST = "SOME_VALUE";
  public static final String STARTED = ofPattern(DT_FORMAT).format(Instant.now());

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

优点:

  • 干净的代码
  • 核心Java
  • 私有构造函数不需要定义
  • 尝试实例化经过验证在编译时,因为java:枚举类型无法实例化
  • 会阻止克隆,并且
  • 无法扩展反序列化(Enum是最终的)
  • 可以使用访问修饰符public / private /(package private)。

The best approach for me, is enum:

public enum SomeApiConstants {;
  // private constant 
  private static final String PREFIX = "/user";
  private static final String DT_FORMAT = "yyyyMMdd HH:mm:ss";

  // public constants
  public static final String SOME_CONST = "SOME_VALUE";
  public static final String STARTED = ofPattern(DT_FORMAT).format(Instant.now());

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

Pros:

  • clean code
  • core Java
  • the private constructor does not need to be defined
  • attempt to instantiate is validated at compile time as java: enum types cannot be instantiated
  • prevents to clone and deserialization
  • cannot be extended (Enum is final)
  • access modifier public/private/(package private) can be used.
手心的温暖 2024-07-19 04:15:36

只需使用最后一堂课。

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

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

Just use final class.

If you want to be able to add other values use an abstract class.

It doesn't make much sense using an interface, an interface is supposed to specify a contract. You just want to declare some constant values.

谜兔 2024-07-19 04:15:36

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

...抱歉,无法抗拒;-)

Or 4. Put them in the class that contains the logic that uses the constants the most

... sorry, couldn't resist ;-)

难理解 2024-07-19 04:15:36
  1. 私有构造函数的缺点之一是永远无法测试方法的存在。

  2. 枚举本质上适合应用于特定领域类型,将其应用于分散常量看起来不够好

    枚举

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

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

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

  1. One of the disadvantage of private constructor is the exists of method could never be tested.

  2. Enum by the nature concept good to apply in specific domain type, apply it to decentralized constants looks not good enough

The concept of Enum is "Enumerations are sets of closely related items".

  1. Extend/implement a constant interface is a bad practice, it is hard to think about requirement to extend a immutable constant instead of referring to it directly.

  2. If apply quality tool like SonarSource, there are rules force developer to drop constant interface, this is a awkward thing as a lot of projects enjoy the constant interface and rarely to see "extend" things happen on constant interfaces

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文