用Java实现常量的最佳方法是什么?
我看过这样的例子:
public class MaxSeconds { public static final int MAX_SECONDS = 25; }
并假设我可以有一个Constants类来包装常量,并声明它们为static final。我几乎不了解Java,并且想知道这是否是创建常量的最佳方法。
解决方案
回答
这是完全可以接受的,甚至可能是标准。
(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)。
回答
我不会称该类与常量相同(除了大小写)……我至少会拥有一类"设置","值"或者"常量",所有常量都将存在。如果我有很多,则将它们分组为逻辑常量类(UserSettings,AppSettings等)。
回答
这是正确的方法。
通常,常量不可保存在单独的"常量"类中,因为它们是不可发现的。如果该常量与当前类相关,则将其保留在该位置有助于下一个开发人员。
回答
只是避免使用接口:
public interface MyConstants { String CONSTANT_ONE = "foo"; } public class NeddsConstant implements MyConstants { }
这很诱人,但是违反了封装并且模糊了类定义的区分。
回答
要更进一步,我们可以在接口中放置全局使用的常量,以便可以在系统范围内使用它们。例如。
public interface MyGlobalConstants { public static final int TIMEOUT_IN_SECS = 25; }
但是,然后不要实施它。通过完全限定的类名直接在代码中引用它们。
回答
枚举呢?
回答
我强烈建议不要使用单个常量类。当时这似乎是个好主意,但是当开发人员拒绝记录常量并且该类增长到包含多达500个彼此都不相关的常量(与应用程序的完全不同的方面)时,这通常会变成完全不可读的常量文件。反而:
- 如果可以访问Java 5+,请使用枚举为应用程序区域定义特定的常量。对于这些常量,应用程序区域的所有部分都应引用枚举,而不是常量值。我们可以声明类似于声明类的枚举。枚举也许是Java 5+的最(也是唯一的)有用的功能。
- 如果常量仅对特定类或者其子类之一有效,则将其声明为protected或者public,然后将其放在层次结构中的顶级类上。这样,子类可以访问这些常量值(如果其他类通过公共访问它们,则这些常量不仅仅对特定类有效...这意味着使用此常量的外部类可能与该常量紧密相关包含常量的类)
- 如果我们有一个定义了行为的接口,但是返回值或者参数值应该是特定的,那么在该接口上定义常量是完全可以接受的,以便其他实现者可以访问它们。但是,请避免创建仅用于保存常量的接口:它可能与仅为保存常量而创建的类一样糟糕。
回答
仅使用接口来保存常量(由Josh Bloch命名为常量接口模式)是不明智的做法。以下是乔什(Josh)的建议:
If the constants are strongly tied to an existing class or interface, you should add them to the class or interface. For example, all of the boxed numerical primitive classes, such as Integer and Double, export MIN_VALUE and MAX_VALUE constants. If the constants are best viewed as members of an enumerated type, you should export them with an enum type. Otherwise, you should export the constants with a noninstantiable utility class.
例子:
// 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; }
关于命名约定:
By convention, such fields have names consisting of capital letters, with words separated by underscores. It is critical that these fields contain either primitive values or references to immutable objects.
回答
在Effective Java(第二版)中,建议我们对常量使用枚举而不是静态整数。
这里有关于Java枚举的不错的文章:
http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html
请注意,在文章结尾处提出的问题是:
So when should you use enums?
回答:
Any time you need a fixed set of constants
回答
我同意使用接口不是行之有效的方法。避免这种模式甚至在Bloch的有效Java中也有它自己的项目(#18)。
Bloch针对常量接口模式提出的一个论点是,使用常量是实现细节,但是实现使用它们的接口会在导出的API中公开该实现细节。
public | private static final TYPE NAME = VALUE;
模式是声明常量的好方法。就个人而言,我认为最好避免创建单独的类来容纳所有常量,但是除了个人喜好和风格之外,我从未见过不这样做的理由。
如果常数可以很好地建模为枚举,请考虑1.5或者更高版本中可用的枚举结构。
如果我们使用的版本早于1.5,我们仍然可以使用普通的Java类提取类型安全的枚举。 (有关更多信息,请参见本网站)。
回答
我们可能犯的第一个错误是创建一个以通用名称调用的全局可访问类,例如常量。这简直是乱七八糟,到处都是垃圾,我们失去了找出系统的哪些部分使用这些常量的全部能力。
相反,常量应该进入"拥有"它们的类。我们是否有一个名为TIMEOUT的常量?它可能应该进入Communications()或者Connection()类。 MAX_BAD_LOGINS_PER_HOUR?进入User()。等等等等。
另一个可能的用途是Java .properties文件,当可以在运行时定义"常量"但用户不容易更改它们时。我们可以将它们打包到.jars中,并使用class resourceLoader引用它们。
回答
对于常量,枚举是恕我直言的更好选择。这是一个例子
公共类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 } }
回答
任何类型的常量都可以通过在类内创建一个不可变的属性来声明(即带有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; }
回答
我这样做的一种方式是通过使用常量值创建一个'Global'类,并在需要访问该常量的类中进行静态导入。
回答
单个通用常量类是个坏主意。常量应该与逻辑上最相关的类组合在一起。
建议不要使用任何类型的变量(尤其是枚举),而应使用方法。创建一个与变量同名的方法,并使其返回我们分配给变量的值。现在删除该变量,并用对我们刚刚创建的方法的调用替换对它的所有引用。如果我们认为常量足够通用,就不必为了使用它而创建类的实例,则可以将常量方法设为类方法。
回答
一个好的面向对象的设计应该不需要许多公共可用的常量。大多数常量应该封装在需要它们完成其工作的类中。
回答
我更喜欢使用getter而不是常量。这些吸气剂可能返回常数值,例如public int getMaxConnections(){return 10;}`,但是任何需要常量的东西都会经过一个吸气剂。
好处之一是,如果程序超出了常量,就会发现它需要可配置,那么我们只需更改getter返回常量的方式即可。
另一个好处是,我们无需重新编译使用该常数的所有内容即可修改该常数。当我们引用静态final字段时,该常量的值将编译为引用该常量的任何字节码。
回答
FWIW,以秒为单位的超时值可能应该是配置设置(从属性文件中读取或者通过Spring中的注入读取),而不是常量。
回答
在单独的类中创建静态最终常量会给我们带来麻烦。 Java编译器实际上将对此进行优化,并将常量的实际值放入引用该常量的任何类中。
如果以后更改'Constants'类,并且不对引用该类的其他类进行硬重新编译,则会使用旧值和新值的组合。
与其将它们视为常量,不如将它们视为配置参数并创建一个类来管理它们。将值设为非最终值,甚至考虑使用吸气剂。将来,当我们确定其中某些参数实际上应由用户或者管理员配置时,它将变得更加容易。
回答
有什么区别
public interface MyGlobalConstants { public static final int TIMEOUT_IN_SECS = 25; }
public class MyGlobalConstants { private MyGlobalConstants () {} // Prevents instantiation public static final int TIMEOUT_IN_SECS = 25; }
并使用
无论何时需要此常量的MyGlobalConstants.TIMEOUT_IN_SECS。我认为两者都一样。