我看过类似这样的例子:
public class MaxSeconds {
public static final int MAX_SECONDS = 25;
}
我想我可以创建一个常量类来包装常量,将它们声明为静态常量。我几乎不懂Java,想知道这是否是创建常量的最佳方式。
我认为使用接口并不是明智之举。避免使用这种模式在Bloch的《Effective Java》中甚至有自己的一项(#18)。
Bloch反对使用常量接口模式的一个论点是,使用常量是一种实现细节,但通过实现一个接口来使用它们,在你导出的API中暴露了这个实现细节。
public|private static final TYPE NAME = VALUE;
模式是声明常量的好方式。个人认为最好避免创建一个单独的类来存放所有的常量,但除了个人偏好和风格外,我从未见过不这样做的理由。
如果您的常量可以很好地建模为枚举,请考虑1.5或更高版本中提供的枚举结构。
如果您使用的版本早于1.5,仍然可以使用普通的Java类来实现类型安全的枚举。(请参见此网站获取更多信息)。
public int getMaxConnections() {return 10;}
,但任何需要常量的东西都将通过getter进行访问。根据上面的评论,我认为这是一种好的方法来改变旧式的全局常量类(具有公共静态最终变量),以其类似于枚举的等效方式:
public class Constants {
private Constants() {
throw new AssertionError();
}
public interface ConstantType {}
public enum StringConstant implements ConstantType {
DB_HOST("localhost");
// other String constants come here
private String value;
private StringConstant(String value) {
this.value = value;
}
public String value() {
return value;
}
}
public enum IntConstant implements ConstantType {
DB_PORT(3128),
MAX_PAGE_SIZE(100);
// other int constants come here
private int value;
private IntConstant(int value) {
this.value = value;
}
public int value() {
return value;
}
}
public enum SimpleConstant implements ConstantType {
STATE_INIT,
STATE_START,
STATE_END;
}
}
如下:
Constants.StringConstant.DB_HOST
public class MyClass{
public static final String ONE_CONSTANT = "value";
public static final String ANOTHER_CONSTANT = "other value";
. . .
}
这里有一个期望参数为以下常量之一的方法:
public void process(String constantExpected){
...
}
process(MyClass.ONE_CONSTANT);
process(MyClass.ANOTHER_CONSTANT);
process("a not defined constant value");
您只有在运行时并且仅在一次检查传输值的情况下才会遇到错误。
使用枚举,无需进行检查,因为客户端只能在枚举参数中传递枚举值。
例如,在此处定义了两个值的枚举类(因此是开箱即用的常量):
public enum MyEnum {
ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");
private String value;
MyEnum(String value) {
this.value = value;
}
...
}
这里有一个期望将其中一种枚举值作为参数的方法:
public void process(MyEnum myEnum){
...
}
process(MyEnum.ONE_CONSTANT);
process(MyEnum.ANOTHER_CONSTANT);
但编译过程不允许您以这种方式调用它:
process("a not defined constant value");
常量应该在哪里声明?
如果您的应用程序包含一个具有特定和强大的功能内聚性的单个现有类,那么1)和2)更直观。
通常,如果这些常量在操作它们的主要类中声明或者有一个非常自然的名字,我们可以猜到会在其中找到它们,这样会更容易使用这些常量。
例如,在JDK库中,指数和pi常量值在一个声明不仅包括常量声明的类中声明(java.lang.Math
)。
public final class Math {
...
public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;
...
}
Math
类。因此,他们可以很容易地找到常量,并且也可以自然地记住 E
和 PI
的定义位置。java.util.concurrent.TimeUnit
枚举类型未在特定类中声明,因为实际上不存在一个而且只有一个 JDK 特定类最直观地承载它。public enum TimeUnit {
NANOSECONDS {
.....
},
MICROSECONDS {
.....
},
MILLISECONDS {
.....
},
SECONDS {
.....
},
.....
}
许多在java.util.concurrent
中声明的类使用它们:
BlockingQueue
, ArrayBlockingQueue<E>
, CompletableFuture
, ExecutorService
等等,似乎没有任何一个更适合容纳枚举。
对于这个问题,有一定的不同意见。首先,在Java中,常量通常被声明为public、static和final。以下是原因:
public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
makes little sense to duplicate them for every object.
final, since they should not be allowed to change
String myConstant = IMyInterface.CONSTANTX;
相反,我会在一些小的权衡之间进行选择,因此取决于您的需求,以下是几种不同的方式可供选择:
1. Use a regular enum with a default/private constructor. Most people would define
constants this way, IMHO.
- drawback: cannot effectively Javadoc each constant member
- advantage: var members are implicitly public, static, and final
- advantage: type-safe
- provides "a limited constructor" in a special way that only takes args which match
predefined 'public static final' keys, thus limiting what you can pass to the
constructor
2. Use a altered enum WITHOUT a constructor, having all variables defined with
prefixed 'public static final' .
- looks funny just having a floating semi-colon in the code
- advantage: you can JavaDoc each variable with an explanation
- drawback: you still have to put explicit 'public static final' before each variable
- drawback: not type-safe
- no 'limited constructor'
3. Use a Class with a private constructor:
- advantage: you can JavaDoc each variable with an explanation
- drawback: you have to put explicit 'public static final' before each variable
- you have the option of having a constructor to create an instance
of the class if you want to provide additional functions related
to your constants
(or just keep the constructor private)
- drawback: not type-safe
4. Using interface:
- advantage: you can JavaDoc each variable with an explanation
- advantage: var members are implicitly 'public static final'
- you are able to define default interface methods if you want to provide additional
functions related to your constants (only if you implement the interface)
- drawback: not type-safe
任何类型的常量都可以通过在类中创建一个不可变属性(即带有final
修饰符的成员变量)来声明。通常还提供static
和public
修饰符。
public class OfficePrinter {
public static final String STATE = "Ready";
}
有很多应用程序中,常量的值表示从 n 元组(例如枚举)中进行选择。在我们的示例中,我们可以选择定义一个枚举类型,以限制可能分配的值(即改进类型安全性):
public class OfficePrinter {
public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
public static final PrinterState STATE = PrinterState.Ready;
}
什么是区别
1.
public interface MyGlobalConstants {
public static final int TIMEOUT_IN_SECS = 25;
}
2。
public class MyGlobalConstants {
private MyGlobalConstants () {} // Prevents instantiation
public static final int TIMEOUT_IN_SECS = 25;
}
并且在需要使用这个常量的地方,使用MyGlobalConstants.TIMEOUT_IN_SECS
。我认为两者是相同的。
一个单一的、通用的常量类是一个不好的想法。常量应该与它们最相关的类一起分组。
与其使用任何类型的变量(特别是枚举),我建议您使用方法。创建一个与变量同名的方法,并使其返回您分配给变量的值。现在删除变量,并将所有引用它的地方替换为对您刚刚创建的方法的调用。如果您觉得这个常量足够通用,不需要创建类的实例来使用它,那么将常量方法设置为类方法。
顺便提一下,超时时间应该作为配置设置(从属性文件中读取或通过Spring注入)而不是常量。