我见过这样的例子:
public class MaxSeconds {
public static final int MAX_SECONDS = 25;
}
并且假设我可以有一个Constants类来包装常量,声明它们是静态final。我几乎不知道Java,我想知道这是否是创建常量的最佳方法。
答案 0 :(得分:403)
这是完全可以接受的,甚至可能是标准。
(public/private) static final TYPE NAME = VALUE;
其中TYPE
是类型,NAME
是包含空格下划线的所有大写字母中的名称,VALUE
是常量值;
我强烈建议不要将常量放在自己的类或接口中。
作为旁注:声明为final且可变的变量仍然可以更改;但是,变量永远不会指向不同的对象。
例如:
public static final Point ORIGIN = new Point(0,0);
public static void main(String[] args){
ORIGIN.x = 3;
}
这是合法的,ORIGIN
将是(3,0)点。
答案 1 :(得分:235)
我强烈建议不要使用单个常量类。当时看起来似乎是一个好主意,但是当开发人员拒绝记录常量并且类增长到包含超过500个常量时,这些常量根本不相关(与应用程序的完全不同的方面有关),通常会变成完全不可读的常量文件。代替:
答案 2 :(得分:120)
BAD PRACTICE 使用接口来保存常量(由Josh Bloch命名为常量接口模式)。以下是Josh的建议:
如果常量紧密相关 你现有的类或接口 应该将它们添加到类或 接口。例如,所有的 盒装数字原始类, 如Integer和Double,导出 MIN_VALUE和MAX_VALUE常量。如果 常量最好被视为 枚举类型的成员,你 应该使用枚举导出它们 类型。否则,你应该导出 具有不可实例化的常量 实用班。
示例:
// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
private PhysicalConstants() { } // Prevents instantiation
public static final double AVOGADROS_NUMBER = 6.02214199e23;
public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
public static final double ELECTRON_MASS = 9.10938188e-31;
}
关于命名惯例:
按照惯例,这些字段有名称 由大写字母组成 由下划线分隔的单词。它是 这些字段包含的关键 原始值或引用 到不可变的对象。
答案 3 :(得分:36)
在Effective Java(第2版)中,建议您使用枚举而不是静态整数来表示常量。
这里有关于Java的枚举的好文章: http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html
请注意,在该文章的最后提出的问题是:
那么什么时候应该使用枚举?
回答:
任何时候你需要一组固定的常量
答案 4 :(得分:21)
避免使用界面:
public interface MyConstants {
String CONSTANT_ONE = "foo";
}
public class NeddsConstant implements MyConstants {
}
这很诱人,但违反了封装并模糊了类定义的区别。
答案 5 :(得分:19)
我使用以下方法:
public final class Constants {
public final class File {
public static final int MIN_ROWS = 1;
public static final int MAX_ROWS = 1000;
private File() {}
}
public final class DB {
public static final String name = "oups";
public final class Connection {
public static final String URL = "jdbc:tra-ta-ta";
public static final String USER = "testUser";
public static final String PASSWORD = "testPassword";
private Connection() {}
}
private DB() {}
}
private Constants() {}
}
例如,我使用Constants.DB.Connection.URL
来获得常量。
对我来说,它看起来更“面向对象”。
答案 6 :(得分:17)
在单独的类中创建静态最终常量会让您遇到麻烦。 Java编译器实际上会对此进行优化,并将常量的实际值放入任何引用它的类中。
如果您稍后更改了“常量”类,并且没有对引用该类的其他类进行重新编译,那么最终将使用旧值和新值的组合。
不要将它们视为常量,而应将它们视为配置参数并创建一个类来管理它们。这些值是非最终的,甚至考虑使用getter。将来,当您确定某些参数实际上应该由用户或管理员配置时,它将更容易实现。
答案 7 :(得分:13)
您可以犯的第一个错误是创建一个全局可访问的类,使用通用名称调用,如常量。这简直就是乱七八糟的垃圾,你失去了弄清楚系统中哪些部分使用这些常量的能力。
相反,常量应该进入“拥有”它们的类。你有一个名为TIMEOUT的常量吗?它可能应该进入您的Communications()或Connection()类。 MAX_BAD_LOGINS_PER_HOUR?进入User()。等等等等。
另一种可能的用途是Java .properties文件,当“常量”可以在运行时定义,但不容易用户更改。您可以将它们打包在.jars中,并使用Class resourceLoader引用它们。
答案 8 :(得分:6)
这是正确的方法。
通常常量不保存在单独的“常量”类中,因为它们不可被发现。如果常量与当前类相关,那么将它们保留在那里有助于下一个开发人员。
答案 9 :(得分:5)
枚举怎么样?
答案 10 :(得分:5)
我同意使用界面不是要走的路。避免这种模式甚至在Bloch的Effective Java中有自己的项目(#18)。
Bloch对常量接口模式的一个参数是使用常量是一个实现细节,但实现一个接口来使用它们会在导出的API中公开该实现细节。
public|private static final TYPE NAME = VALUE;
模式是声明常量的好方法。就个人而言,我认为最好避免单独设置一个容纳所有常量的课程,但除了个人偏好和风格外,我从未见过不这样做的理由。
如果您的常量可以作为枚举进行良好建模,请考虑1.5或更高版本中可用的enum结构。
如果您使用的是1.5之前的版本,您仍然可以使用普通的Java类来提取类型安全枚举。 (有关详细信息,请参阅this site。)
答案 11 :(得分:5)
我更喜欢使用getter而不是常量。那些吸气剂可能会返回常数值,例如public int getMaxConnections() {return 10;}
,但任何需要常数的东西都会通过吸气剂。
一个好处是,如果你的程序超出常量 - 你发现它需要是可配置的 - 你可以改变getter返回常量的方式。
另一个好处是,为了修改常量,您不必重新编译使用它的所有内容。当您引用静态final字段时,该常量的值将被编译为引用它的任何字节码。
答案 12 :(得分:4)
基于上面的评论,我认为这是一种很好的方法,可以通过以下方式将旧式的全局常量类(具有公共静态最终变量)更改为类似枚举的等效类:
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
答案 13 :(得分:3)
良好的面向对象设计不需要许多公开可用的常量。大多数常量应该封装在需要它们完成工作的类中。
答案 14 :(得分:2)
有一定的意见来回答这个问题。首先,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
我永远不会为CONSTANTS访问器/对象使用接口,因为通常需要实现接口。这看起来不好笑:
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
答案 15 :(得分:2)
在Java中实现常量的最佳方法是什么?
我们应该避免的一种方法:使用接口来定义常量。
专门创建一个声明常量的接口实际上是最糟糕的事情:它破坏了接口设计的原因:定义方法合同。
即使已经存在一个接口来满足特定需求,声明其中的常量也没有意义,因为常量不应该成为API的一部分并且合同提供给客户端类。
为简化起见,我们有广泛的4种有效方法。
使用static final String/Integer
字段:
使用Java 5 enum
:
TLDR:找到常量的最佳方法是哪种?
在大多数情况下,枚举方式可能比static final String/Integer
方式更精细,我个人认为只有在我们有充分理由的情况下才应使用static final String/Integer
方式不使用枚举。
关于我们应该声明常量值的位置,的想法是搜索是否存在具有常量值的特定且强大的功能内聚的单个现有类。如果我们找到这样的类,我们应该将它作为常量持有者。否则,常量应与任何特定类无关。
static final String
/ static final Integer
与enum
Enums的使用确实是一种强烈考虑的方式
与String
或Integer
常量字段相比,枚举具有很大的优势。
他们设置了更强大的编译约束。
如果定义一个以枚举作为参数的方法,则只能传递枚举类中定义的枚举值(或null)。
使用String和Integer,您可以使用兼容类型的任何值替换它们,即使该值不是static final String
/ static final Integer
字段中的已定义常量,编译也会正常。
例如,在类中定义为static 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);
或
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
以非常自然的方式定义的位置。
如果您的应用程序不包含与常量值具有非常特定且强大的功能内聚力的现有类,则1个变体和2个变体)方式看起来更直观。
一般来说,如果在一个操作它们的类中声明这些常量,它们不会简化常量的使用,而我们还有3个或4个其他操作它们的类,并且这些类中没有一个看起来比其他类更自然。主机常数值
在这里,定义一个只保留常量值的自定义类是有道理的
例如,在JDK库中,java.util.concurrent.TimeUnit
枚举未在特定类中声明,因为实际上并不存在唯一一个看起来最直观的JDK特定类:
public enum TimeUnit {
NANOSECONDS {
.....
},
MICROSECONDS {
.....
},
MILLISECONDS {
.....
},
SECONDS {
.....
},
.....
}
java.util.concurrent
中声明的许多类使用它们:
BlockingQueue
,ArrayBlockingQueue<E>
,CompletableFuture
,ExecutorService
,......实际上没有一个人更适合举行枚举。
答案 16 :(得分:1)
单个通用常量类是个坏主意。常量应该与它们在逻辑上最相关的类组合在一起。
我建议您使用方法,而不是使用任何类型的变量(尤其是枚举)。创建一个与变量同名的方法,并让它返回您赋给变量的值。现在删除变量并用对刚刚创建的方法的调用替换对它的所有引用。如果你认为常量足够通用,你不必创建类的实例只是为了使用它,那么使常量方法成为一个类方法。
答案 17 :(得分:1)
FWIW,以秒为单位的超时值应该是配置设置(从属性文件中读取或通过Spring中的注入读取)而不是常量。
答案 18 :(得分:1)
任何类型的常量都可以通过在类中创建一个不可变属性(即具有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;
}
答案 19 :(得分:1)
有什么区别
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
只要我们需要这个常数。我认为两者都是一样的。
答案 20 :(得分:0)
我同意大多数人所说的,在处理常量集合时最好使用枚举。但是,如果您使用Android进行编程,则可以使用更好的解决方案:IntDef Annotation。
@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();
IntDef注释以一种简单的方式优于枚举,因为它只是一个编译时标记,所以占用的空间要少得多。它不是一个类,也没有自动字符串转换属性。
答案 21 :(得分:0)
坏习惯,非常可怕 恼人的做法引用Joshua Bloch而不理解基本的零基本原理。
我没有读过Joshua Bloch的任何内容,所以
正如圣经原教旨主义一样,所有圣经的律法都可以用
来概括类似的软件工程原教旨主义可以通过
来概括此外,在圣经的原教旨主义者圈子中,得出了一个强有力的合理推论
同样地,如果你不尊重自己作为一个程序员,只是接受一些编程大师的声明和预言而不询问基本原则,你的引用和对Joshua Bloch(等等)的依赖是毫无意义的。因此,你实际上不会尊重你的同事。
软件编程的基本规律
根据什么样的基本有效和负责任的节目制定这个宗教法令?
请阅读关于接口模式常量(https://en.wikipedia.org/wiki/Constant_interface)的维基百科文章,以及它针对接口模式常量所陈述的愚蠢借口。
Whatif-No IDE?作为软件程序员,谁在地球上不会使用IDE?我们大多数人都是程序员,他们宁愿不必证明拥有男子气概的生存主义,也不必使用IDE。
使用当前范围内未使用的变量污染命名空间?它可能是这种观点的支持者
使用接口来强制执行常量是滥用接口。支持者有这样的坏习惯
将来很难将接口转换为已实现的类。哈......嗯...... ???
无论有什么借口,对于基本有效的软件工程来说,没有任何有效的排除方式可以合法化或者通常不鼓励使用界面常量。
制定美国宪法的创始人的原始意图和心理状态是什么并不重要。我们可以辩论创始人的原始意图,但我所关心的只是美国宪法的书面陈述。每个美国公民都有责任利用美国宪法中的书面文学原教旨主义,而不是不成文的创始意图。
同样,我不在乎&#34;原来&#34; Java平台和编程语言的创始人的意图有接口。我关心的是Java规范提供的有效功能,我打算充分利用这些功能来帮助我实现负责任的软件编程的基本规律。如果我被认为违反了接口的意图,我就不在乎了#34;。我不在乎Gosling或Bloch所说的关于使用Java&#34;的正确方法,除非他们所说的并不违反我对有效实现基本原则的需求。
托管或传输数据模型的方式并不重要。无论您是使用接口还是枚举或whatevernot,关系型还是非SQL,如果您不了解数据模型规范化的需要和过程。
我们必须首先定义和规范化一组流程的数据模型。当我们拥有一个连贯的数据模型时,我们才能使用其组件的流程来定义功能行为,并处理块应用程序的字段或领域。只有这样我们才能定义每个功能过程的API。
即使是EF Codd提出的数据规范化的各个方面,现在也面临严峻挑战和严峻挑战。例如他对1NF的陈述被批评为含糊不清,错位和过度简化,以及他的其他陈述,尤其是现代数据服务,回购技术和传播的出现。国际海事组织,EF Codd的陈述应该完全抛弃,并设计一套更为数学上合理的新陈述。
EF Codd's的一个明显缺陷及其与有效人类理解错位的原因是他相信人类可感知的多维,可变维数据可以通过一组零碎的二维映射有效地被感知
EF Codd没有表达的意思。
在每个相干数据模型中,这些是数据模型一致性的顺序分级顺序。
在服务间组件应用程序的字段或网格中,必须存在一个且仅有一个相干数据模型,或者存在用于标识数据的数据模型/版本的方法。
有些数据规范化问题比这个世俗问题更重要。如果你不解决这些问题,那么你认为界面常数引起的混淆就相对没有了。齐尔希。
从数据模型规范化开始,然后将组件确定为变量,将属性视为合约接口常量。
然后确定哪个进入值注入,属性配置占位,接口,最终字符串等。
如果你不得不使用需要找到一个更容易指示接口常量的组件的借口,那就意味着你养成了不习惯数据模型规范化的坏习惯。
也许您希望将数据模型编译为vcs版本。您可以提取一个明显可识别的数据模型版本。
接口中定义的值完全保证不可变。并且可以分享。当你需要的是那组常量时,为什么要从另一个类中将一组最终字符串加载到你的类中?
那为什么不发布数据模型合同呢?我的意思是,如果你能够连贯地管理和规范它,为什么不呢? ...
public interface CustomerService {
public interface Label{
char AssignmentCharacter = ':';
public interface Address{
String Street = "Street";
String Unit= "Unit/Suite";
String Municipal = "City";
String County = "County";
String Provincial = "State";
String PostalCode = "Zip"
}
public interface Person {
public interface NameParts{
String Given = "First/Given name"
String Auxiliary = "Middle initial"
String Family = "Last name"
}
}
}
}
现在我可以参考我的应用程序&#39;以诸如
之类的方式签订合同标签CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family
这会混淆jar文件的内容?作为一名Java程序员,我并不关心jar的结构。
这为osgi推动的运行时交换带来了复杂性? Osgi是一种非常有效的方法,可以让程序员继续养成坏习惯。有比osgi更好的选择。
或者为什么不呢?私人常数没有泄露到公布的合同中。所有私有常量都应该被分组为一个名为&#34; Constants&#34;的私有接口,因为我不想搜索常量而且我懒得重复键入&#34; private final String&# 34。
public class PurchaseRequest {
private interface Constants{
String INTERESTINGName = "Interesting Name";
String OFFICIALLanguage = "Official Language"
int MAXNames = 9;
}
}
也许就是这样:
public interface PurchaseOrderConstants {
public interface Properties{
default String InterestingName(){
return something();
}
String OFFICIALLanguage = "Official Language"
int MAXNames = 9;
}
}
接口常量值得考虑的唯一问题是接口何时实现。
这不是&#34;初衷&#34;接口?就像我会关心&#34;初衷&#34;创始人制定美国宪法,而不是最高法院如何解释美国宪法的书面信件???
毕竟,我生活在勇敢的自由,野性和家园之地。勇敢,自由,狂野 - 使用界面。如果我的同事们拒绝使用高效和懒惰的编程方法,那么我是否有必要通过黄金法则来降低我的编程效率以与他们的编程保持一致?也许我应该,但那不是一个理想的情况。
答案 22 :(得分:0)
我使用static final
声明常量并使用ALL_CAPS命名表示法。我已经看到了很多真实生活实例,其中所有常量都聚集在一起形成一个接口。一些帖子正确地称这是一种不好的做法,主要是因为这不是一个界面的用途。接口应该强制执行一个契约,并且不应该放置不相关的常量。如果常量语义不属于特定的类,那么将它放在一个无法实例化的类中(通过私有构造函数)也是可以的。 ES)。我总是在课堂上放一个与它最相关的常数,因为这是有道理的,也很容易维护。
枚举是表示一系列值的不错选择,但如果要存储独立常量并强调绝对值(例如,TIMEOUT = 100 ms),则可以采用static final
方法。
答案 23 :(得分:0)
static final
是我的偏好,如果该项目确实可以枚举,我只会使用enum
。
答案 24 :(得分:0)
我这样做的一种方法是创建一个带有常量值的'Global'类,并在需要访问常量的类中进行静态导入。
答案 25 :(得分:0)
对于常数,Enum是更好的选择恕我直言。这是一个例子
公共类myClass {
public enum myEnum {
Option1("String1", 2),
Option2("String2", 2)
;
String str;
int i;
myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }
}
答案 26 :(得分:0)
为了更进一步,您可以将全局使用的常量放在接口中,以便可以在系统范围内使用它们。 E.g。
public interface MyGlobalConstants {
public static final int TIMEOUT_IN_SECS = 25;
}
但是不要实施它。只需通过完全限定的类名在代码中直接引用它们。
答案 27 :(得分:0)
我不会将该类称为相同的(除了大小写)作为常量...我将至少有一类“设置”,或“值”,或“常量”,其中所有常量会活下去的如果我有大量的,我会将它们分组为逻辑常量类(UserSettings,AppSettings等)