我看过这样的例子:
public class MaxSeconds {
public static final int MAX_SECONDS = 25;
}
并假设我可以有一个Constants类来包装常量,并声明它们为static final。我几乎不了解Java,并且想知道这是否是创建常量的最佳方法。
我看过这样的例子:
public class MaxSeconds {
public static final int MAX_SECONDS = 25;
}
并假设我可以有一个Constants类来包装常量,并声明它们为static final。我几乎不了解Java,并且想知道这是否是创建常量的最佳方法。
Answers:
这是完全可以接受的,甚至可能是标准。
(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)。
我强烈建议不要使用单个常量类。当时这似乎是个好主意,但是当开发人员拒绝记录常量并且该类增长到包含多达500个完全不相关的常量(与应用程序的完全不同的方面)时,这通常会变成完全不可读的常量文件。代替:
这是一个坏习惯使用的界面,以保持常量(命名常量接口模式由乔希布洛赫)。这是乔希的建议:
如果常量与现有的类或接口紧密关联,则应将其添加到类或接口。例如,所有装箱的数值基元类(例如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;
}
关于命名约定:
按照惯例,此类字段的名称由大写字母组成,单词之间用下划线分隔。这些字段包含原始值或对不可变对象的引用至关重要。
abstract
在类中使用表示法,而不要使用私有构造函数。
abstract
而不是私有构造函数并不能完全阻止实例化,因为可以将其子类化并实例化子类(这样做不是一个好主意,但有可能)。@ToolmakerSteve不能使用私有构造函数对类进行子类化(至少在没有严重的黑手的情况下也不能这样),因为子类的构造函数需要调用其超类的(现在是私有的)构造函数。因此,标记它final
是不必要的(但可能更明确)。
在Effective Java(第二版)中,建议对常量使用枚举而不是静态整数。
这里有关于Java枚举的不错的文章:http : //java.sun.com/j2se/1.5.0/docs/guide/language/enums.html
请注意,在文章结尾处提出的问题是:
那么什么时候应该使用枚举?
回答:
任何时候需要固定的常量集
只是避免使用接口:
public interface MyConstants {
String CONSTANT_ONE = "foo";
}
public class NeddsConstant implements MyConstants {
}
这很诱人,但是违反了封装并且模糊了类定义的区分。
我使用以下方法:
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
用来获得常数。对我来说,它看起来更“面向对象”。
在单独的类中创建静态最终常量会给您带来麻烦。Java编译器实际上将对此进行优化,并将常量的实际值放入引用该常量的任何类中。
如果以后更改'Constants'类,并且不对引用该类的其他类进行硬重新编译,则会使用新旧值的组合。
与其将它们视为常量,不如将它们视为配置参数并创建一个类来管理它们。将值设为非最终值,甚至考虑使用吸气剂。将来,当您确定其中某些参数实际上应由用户或管理员配置时,它将变得更加容易。
您可能犯的第一个错误是创建一个以通用名称调用的全局可访问类,例如常量。这简直是乱七八糟,到处都是垃圾,您失去了找出系统的哪些部分使用这些常量的全部能力。
相反,常量应该进入“拥有”它们的类。您是否有一个名为TIMEOUT的常量?它可能应该进入您的Communications()或Connection()类。MAX_BAD_LOGINS_PER_HOUR?进入User()。等等等等。
另一个可能的用途是Java .properties文件,当可以在运行时定义“常量”,但用户不容易更改它们时。您可以将它们打包到您的.jar中,并使用class resourceLoader引用它们。
这是正确的方法。
通常,常量不可保存在单独的“常量”类中,因为它们是不可发现的。如果该常量与当前类相关,则将其保留在该位置有助于下一个开发人员。
我更喜欢使用getter而不是常量。这些吸气剂可能返回常数值,例如public int getMaxConnections() {return 10;}
,但是任何需要该常量的东西都会经过吸气剂。
好处之一是,如果您的程序超出了常量,就会发现该常量必须是可配置的,您只需更改getter返回常量的方式即可。
另一个好处是,为了修改常量,您不必重新编译使用该常量的所有内容。当您引用静态final字段时,该常量的值将编译为引用该常量的任何字节码。
我同意使用接口不是解决之道。避免这种模式甚至在Bloch的Effective Java中有其自己的项目(#18)。
Bloch与常量接口模式相对的一个论点是,使用常量是实现细节,但是实现使用它们的接口会在导出的API中公开该实现细节。
的 public|private static final TYPE NAME = VALUE;
模式是声明不变的好方法。就个人而言,我认为最好避免创建单独的类来容纳所有常量,但是除了个人喜好和风格之外,我从未见过不这样做的理由。
如果您的常量可以很好地建模为枚举,请考虑枚举 1.5或更高版本中可用结构。
如果您使用的版本早于1.5,仍然可以使用常规Java类提取类型安全的枚举。(有关更多信息,请参见本网站)。
基于以上评论,我认为这是一种将老式的全局常量类(具有公共静态最终变量)更改为类似于枚举的等效方法,如下所示:
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中的常量通常被声明为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
用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
枚举的使用确实是一种值得深思的方法。
枚举在字段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
,...确实没有他们中的一个似乎更适合持有枚举。
可以通过在类内创建一个不可变属性(即带有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
在需要此常量的任何地方使用
。我认为两者都一样。
我不会称该类与常量相同(除了大小写)……我至少会拥有一类“设置”,“值”或“常量”,所有常量都将存在。如果我有很多,则将它们分组为逻辑常量类(UserSettings,AppSettings等)。
我用 static final
用来声明常量,并使用ALL_CAPS命名符号。我已经看到了很多现实生活中的实例,其中所有常量都捆绑在一起形成一个接口。一些帖子正确地将其称为不好的做法,主要是因为这不是接口的用途。接口应强制执行合同,并且不应放置无关的常量。如果常量的语义不属于特定的类,则将其放到无法实例化(通过私有构造函数)的类中也可以。 es)。我总是在与它最相关的类中放置一个常量,因为这很有意义并且也易于维护。
枚举是表示一个值范围的不错选择,但是如果您要存储独立常量,并且强调绝对值(例如TIMEOUT = 100 ms),则可以采用该static final
方法。
我同意大多数人的说法,在处理常量集合时最好使用枚举。但是,如果您使用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注释以一种简单的方式优于枚举,因为它只是一个编译时标记,所以占用的空间要少得多。它不是一个类,也不具有自动字符串转换属性。
引用约书亚·布洛赫(Joshua Bloch)却不了解基本的零基础原教旨主义,这是一种不良习惯和令人讨厌的做法。
我什么都没读,约书亚·布洛赫(Joshua Bloch)
就像圣经中的原教旨主义一样,所有圣经定律都可以用
因此,类似地,软件工程原教旨主义可以归纳为
此外,在圣经的原教旨主义者圈子中,得出了强有力而合理的推论。
同样,如果您不尊重自己作为程序员,而只是接受某些编程大师的声明和预言而又不质疑基础知识,那么您对Joshua Bloch(等等)的引用和依赖是毫无意义的。因此,您实际上不会尊重您的程序员。
软件编程的基本定律
根据什么根本有效和负责任的编程法则,该宗教法令应属于哪些法律?
只需阅读有关接口模式常量的Wikipedia文章(https://en.wikipedia.org/wiki/Constant_interface),愚蠢的借口就针对接口模式常量声明了这种说法。
如果没有IDE?作为软件程序员,到底谁会不使用IDE?我们大多数人都是程序员,他们更愿意不必为了避免使用IDE而证明自己具有男子气概的生存主义主义。
使用当前范围内未使用的变量污染名称空间?可能是这种观点的支持者
使用接口强制执行常量会滥用接口。支持者有这样的坏习惯
将来,即使不是不可能,将接口转换为已实现的类也是很困难的。哈....嗯... ???
无论有什么借口,在根本有效的软件工程中对接口常数进行合法化或普遍不鼓励使用时,都没有合法的借口。
制定《美国宪法》的开国元勋的初衷和心理状态并不重要。我们可以辩论开国元勋的初衷,但我所关心的只是美国宪法的书面声明。每个美国公民都有责任利用书面的文学原教旨主义而非美国宪法的非书面的创始意图。
同样,我不在乎Java平台和编程语言的创始人对于接口的“原始”意图。我关心的是Java规范提供的有效功能,并且我打算充分利用这些功能,以帮助我实现负责任的软件编程的基本定律。我不在乎是否被认为“违反了界面的意图”。我不在乎Gosling或Bloch所说的“正确使用Java的方式”,除非他们所说的不违反我对有效实现基本原理的需求。
数据模型的托管或传输方式无关紧要。如果您不了解数据模型规范化的需求和过程,则无论是使用接口,枚举或其他任何东西,关系式SQL还是无SQL。
我们必须首先定义并标准化一组流程的数据模型。而且,当我们拥有一致的数据模型时,我们只能使用其组件的流程来定义功能行为,并限制应用程序的领域或领域。只有这样,我们才能定义每个功能过程的API。
甚至EF Codd提出的数据标准化方面也受到了严峻挑战和严峻挑战。例如,他对1NF的声明被批评为含糊,不统一和过于简化,尤其是在现代数据服务,回购技术和传输出现时,他的其余声明也受到批评。IMO,应该完全放弃EF Codd语句,并设计一套在数学上更合理的新语句。
EF Codd的一个明显缺陷及其导致无法有效地理解人类的原因是他相信可以通过一系列零散的二维映射来有效地感知人类可感知的多维可变维度数据。
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"
}
}
}
}
现在,我可以通过以下方式引用应用的合同规定的标签:
CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family
这混淆了jar文件的内容?作为Java程序员,我不在乎jar的结构。
这给以osgi为动力的运行时交换带来了复杂性。Osgi是允许程序员继续养成不良习惯的极为有效的手段。有比osgi更好的选择。
还是为什么不呢?私有常量不会泄漏到已发布的合同中。所有私有常量都应归入名为“ Constants”的私有接口中,因为我不想搜索常量,而且我懒于重复输入“ private final String”。
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;
}
}
值得考虑的唯一的接口常量问题是何时实现接口。
这不是接口的“原始意图”吗?就像我会关心开国元勋在制定《美国宪法》时的“原始意图”一样,而不是最高法院将如何解释《美国宪法》的书面文字?
毕竟,我生活在自由,荒野和勇敢者之乡的土地上。勇敢,自由,疯狂-使用界面。如果我的程序员程序员拒绝使用高效且懒惰的编程方式,那么我是否有遵守黄金法则的义务,那就是降低我的编程效率以适应他们的编程习惯?也许我应该这样做,但这不是理想的情况。