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

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

public static final String SOME_CONST = "SOME_VALUE";

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

  1. 接口
  2. 抽象类
  3. 期末考试

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


对一些答案的澄清:

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

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

143432 次浏览

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.

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

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)) {
//...
}

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.

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

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

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.

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.

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

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.

  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

The best approach for me, is 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}";
}
}

Pros:

  • clean code
  • the private constructor does not need to be defined
  • attempt to instantiate is validated in compile time as java: enum types may not be instantiated
  • prevents to clone and deserialization