我见过这样的例子:
public class MaxSeconds { public static final int MAX_SECONDS = 25; }
并且假设我可以有一个Constants类来包装常量,声明它们是静态final.我几乎不知道Java,我想知道这是否是创建常量的最佳方法.
这是完全可以接受的,甚至可能是标准.
(public/private) static final TYPE NAME = VALUE;
TYPE
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个常量时,这些常量根本不相关(与应用程序的完全不同的方面有关),通常会变成完全不可读的常量文件.代替:
如果您可以访问Java 5+,请使用枚举来定义应用程序区域的特定常量.对于这些常量,应用程序区域的所有部分都应引用枚举,而不是常量值.您可以声明类似于声明类的枚举.枚举可能是Java 5+中最有用(也可以说是唯一)的有用功能.
如果您拥有仅对特定类或其子类之一有效的常量,请将它们声明为protected或public,并将它们放在层次结构中的顶级类中.这样,子类可以访问这些常量值(如果其他类通过public访问它们,则常量不仅对特定类有效...这意味着使用此常量的外部类可能与包含常量的类)
如果您有一个定义了行为的接口,但返回的值或参数值应该是特定的,那么在该接口上定义常量是完全可以接受的,这样其他实现者就可以访问它们.但是,避免创建一个仅用于保存常量的接口:它可能变得像为保持常量而创建的类一样糟糕.
使用接口只是为了保持常量(由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; }
关于命名约定:
按照惯例,这些字段的名称由大写字母组成,单词由下划线分隔.这些字段包含原始值或对不可变对象的引用至关重要.
在Effective Java(第2版)中,建议您使用枚举而不是静态整数来表示常量.
这里有关于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编译器实际上会对此进行优化,并将常量的实际值放入任何引用它的类中.
如果您稍后更改了"常量"类,并且您没有对引用该类的其他类进行硬重新编译,那么最终将使用旧值和新值的组合.
不要将它们视为常量,而应将它们视为配置参数并创建一个类来管理它们.这些值是非最终的,甚至考虑使用getter.将来,当您确定某些参数实际上应该由用户或管理员配置时,它将更容易实现.
您可以犯的第一个错误是创建一个全局可访问的类,使用通用名称调用,如常量.这简直就是乱七八糟的垃圾,你失去了弄清楚系统中哪些部分使用这些常量的能力.
相反,常量应该进入"拥有"它们的类.你有一个名为TIMEOUT的常量吗?它可能应该进入您的Communications()或Connection()类.MAX_BAD_LOGINS_PER_HOUR?进入User().等等等等.
另一种可能的用途是Java .properties文件,当"常量"可以在运行时定义,但不容易用户更改.您可以将它们打包在.jars中,并使用Class resourceLoader引用它们.
这是正确的方法.
通常,常量不会保存在单独的"常量"类中,因为它们不可发现.如果常量与当前类相关,那么将它们保留在那里有助于下一个开发人员.
枚举怎么样?
我同意使用界面不是要走的路.在Bloch的Effective Java中,避免这种模式甚至有自己的项目(#18).
Bloch对常量接口模式的一个参数是使用常量是一个实现细节,但实现一个接口来使用它们会在导出的API中公开该实现细节.
该public|private static final TYPE NAME = VALUE;
模式是声明常量的好方法.就个人而言,我认为最好避免单独设置一个容纳你所有常数的课程,但除了个人偏好和风格外,我从未见过不这样做的理由.
如果您的常量可以作为枚举进行良好建模,请考虑1.5或更高版本中可用的枚举结构.
如果您使用的是1.5之前的版本,则仍然可以使用普通的Java类来提取类型安全枚举.(有关详细信息,请参阅此网站).
我更喜欢使用getter而不是常量.那些getter可能会返回常量值,例如public int getMaxConnections() {return 10;}
,但是任何需要常量的东西都会经过一个getter.
一个好处是,如果你的程序超出常量 - 你发现它需要是可配置的 - 你可以改变getter返回常量的方式.
另一个好处是,为了修改常量,您不必重新编译使用它的所有内容.当您引用静态final字段时,该常量的值将编译为引用它的任何字节码.