我见过这样的例子:
public class MaxSeconds {
public static final int MAX_SECONDS = 25;
}
假设我可以有一个Constants类来包装常量,并将它们声明为静态final。我几乎不知道Java,我想知道这是否是创建常量的最佳方式。
我见过这样的例子:
public class MaxSeconds {
public static final int MAX_SECONDS = 25;
}
假设我可以有一个Constants类来包装常量,并将它们声明为静态final。我几乎不知道Java,我想知道这是否是创建常量的最佳方式。
当前回答
您可能犯的第一个错误是创建一个全局可访问的类,类名为泛型名称,如Constants。这只会充斥着垃圾,您将无法确定系统的哪个部分使用了这些常量。
相反,常量应该放到“拥有”它们的类中。有一个叫TIMEOUT的常量吗?它应该放到Communications()或Connection()类中。MAX_BAD_LOGINS_PER_HOUR吗?进入User()。诸如此类。
当“常量”可以在运行时定义,但用户不容易更改时,另一种可能的用法是Java .properties文件。你可以把它们打包到你的.jar文件中,并使用Class resourceLoader引用它们。
其他回答
任何类型的常量都可以通过在类中创建一个不可变属性(即带有final修饰符的成员变量)来声明。通常还提供静态和公共修饰符。
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;
}
我强烈建议不要只使用一个常量类。这在当时看起来是一个好主意,但是当开发人员拒绝记录常量,并且类增长到包含500个以上彼此完全不相关的常量(与应用程序的完全不同方面相关)时,通常会导致常量文件完全不可读。而不是:
If you have access to Java 5+, use enums to define your specific constants for an application area. All parts of the application area should refer to enums, not constant values, for these constants. You may declare an enum similar to how you declare a class. Enums are perhaps the most (and, arguably, only) useful feature of Java 5+. If you have constants that are only valid to a particular class or one of its subclasses, declare them as either protected or public and place them on the top class in the hierarchy. This way, the subclasses can access these constant values (and if other classes access them via public, the constants aren't only valid to a particular class...which means that the external classes using this constant may be too tightly coupled to the class containing the constant) If you have an interface with behavior defined, but returned values or argument values should be particular, it is perfectly acceptible to define constants on that interface so that other implementors will have access to them. However, avoid creating an interface just to hold constants: it can become just as bad as a class created just to hold constants.
根据上面的评论,我认为这是一个很好的方法,将老式的全局常量类(具有公共静态final变量)更改为类似枚举的等价物,如下所示:
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
在Java中实现常量的最佳方法是什么?
我们应该避免的一种方法是:使用接口来定义常量。
创建专门用于声明常量的接口实际上是最糟糕的事情:它违背了设计接口的初衷:定义方法契约。
即使已经存在一个接口来满足特定的需求,在其中声明常量也没有意义,因为常量不应该成为API和提供给客户端类的契约的一部分。
为了简化,我们有4种有效的方法。
使用静态的最终字符串/整数字段:
1)使用在内部声明常量的类。 1变体)创建一个专门用于声明常量的类。
Java 5 enum:
2)在相关的目的类(嵌套类)中声明枚举。 2变体)创建枚举作为一个独立的类(在它自己的类文件中定义)。
TLDR:哪个是最好的方法,在哪里找到常数?
In most of cases, the enum way is probably finer than the static final String/Integer way and personally I think that the static final String/Integer way should be used only if we have good reasons to not use enums. And about where we should declare the constant values, the idea is to search whether there is a single existing class that owns a specific and strong functional cohesion with constant values. If we find such a class, we should use it as the constants holder. Otherwise, the constant should be associated to no one particular class.
静态final字符串/静态final整数vs enum
Enums usage is really a way to strongly considered. Enums have a great advantage over String or Integer constant field. They set a stronger compilation constraint. If you define a method that takes the enum as parameter, you can only pass a enum value defined in the enum class(or null). With String and Integer you can substitute them with any values of compatible type and the compilation will be fine even if the value is not a defined constant in the static final String/ static final Integer fields.
例如,下面两个在类中定义为静态final String字段的常量:
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);
or
process(MyClass.ANOTHER_CONSTANT);
但是没有编译约束阻止你以这种方式调用它:
process("a not defined constant value");
只有在运行时才会出现错误,并且只有在一次检查传输的值时才会出现错误。
对于enum,不需要检查,因为客户端只能在enum参数中传递enum值。
例如,这里有两个在枚举类中定义的值(所以是常量):
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);
or
process(MyEnum.ANOTHER_CONSTANT);
但是编译永远不会允许你以这种方式调用它:
process("a not defined constant value");
我们应该在哪里声明常数?
如果您的应用程序包含一个现有的类,该类拥有特定的和强大的常量值函数内聚,则1)和2)看起来更直观。 一般来说,如果常量是在操纵它们的主类中声明的,或者有一个很自然的名字,我们可以在里面找到它,那么使用起来会更容易。
例如,在JDK库中,在一个不仅声明常量声明的类(java.lang.Math)中声明了指数和π常数值。
public final class Math {
...
public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;
...
}
使用数学函数的客户端经常依赖于Math类。 因此,他们可以很容易地找到常数,也可以很自然地记住E和的定义。
If your application doesn't contain an existing class that has a very specific and strong functional cohesion with the constant values, the 1 variant) and the 2 variant) ways appear more intuitive. Generally, it doesn't ease the use of the constants if these are declared in one class that manipulates them while we have also 3 or 4 other classes that manipulate them as much as and no one of these classes seems be more natural than others to host constant values. Here, defining a custom class to hold only constant values makes sense. For example in the JDK library, the java.util.concurrent.TimeUnit enum is not declared in a specific class as there is not really one and only one JDK specific class that appear as the most intuitive to hold it :
public enum TimeUnit {
NANOSECONDS {
.....
},
MICROSECONDS {
.....
},
MILLISECONDS {
.....
},
SECONDS {
.....
},
.....
}
在java.util.concurrent中声明的许多类都使用它们: BlockingQueue, ArrayBlockingQueue<E>, CompletableFuture, ExecutorService,…实际上,似乎没有谁比他们更适合主持这次全会。
我同意使用界面不是正确的方法。在Bloch的《Effective Java》中,避免这种模式甚至有自己的项目(#18)。
Bloch反对常量接口模式的一个论点是,常量的使用是一个实现细节,但是实现一个使用它们的接口会在导出的API中暴露该实现细节。
public|private static final TYPE NAME = VALUE;模式是一种声明常数的好方法。就我个人而言,我认为最好避免创建一个单独的类来存放所有的常量,但除了个人偏好和风格之外,我还没有看到不这样做的理由。
如果常量可以很好地建模为枚举,请考虑1.5或更高版本中可用的枚举结构。
如果您使用的是1.5以前的版本,您仍然可以通过使用普通的Java类来实现类型安全枚举。(详见这个网站)。