在Java中实现常数的最佳方法是什么?

What is the best way to implement constants in Java?

我见过这样的例子:

1
2
3
public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

假设我可以有一个常量类来包装常量,声明它们为静态final。我几乎完全不知道Java,我想知道这是否是创建常量的最好方法。


这是完全可以接受的,甚至可能是标准。

1
(public/private) static final TYPE NAME = VALUE;

其中TYPE为类型,NAME为所有大写字母中的名称,用下划线表示空格,VALUE为常量值;

我强烈建议不要将常量放在它们自己的类或接口中。

附带说明:声明为最终变量且可变的变量仍然可以更改;但是,变量永远不能指向其他对象。

例如:

1
2
3
4
5
6
7
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 +中最(也可以说是唯一)有用的特性。
  • 如果有只对特定类或其子类有效的常量,请将它们声明为受保护或公共的,并将它们放在层次结构中的顶级类中。这样,子类就可以访问这些常量值(如果其他类通过public访问这些常量,那么这些常量不仅对特定的类有效……这意味着使用该常量的外部类可能与包含该常量的类耦合得过紧)
  • 如果您有一个定义了行为的接口,但是返回的值或参数值应该是特定的,那么在该接口上定义常量是完全可以接受的,这样其他实现者就可以访问这些常量。但是,避免创建一个只保存常量的接口:它可能会变得和创建只保存常量的类一样糟糕。


使用接口来保存常量(由JoshBloch命名的常量接口模式)是一个糟糕的实践。乔希的建议是:

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.

例子:

1
2
3
4
5
6
7
8
9
// 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.


在有效的Java(第二版)中,建议使用枚举而不是静态的int来实现常量。

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


只需避免使用接口:

1
2
3
4
5
6
7
public interface MyConstants {
    String CONSTANT_ONE ="foo";
}

public class NeddsConstant implements MyConstants {

}

它很诱人,但违背了封装,模糊了类定义的区别。


我使用以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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。将来,当您确定这些参数中的一些实际上应该由用户或管理员配置时,这样做会容易得多。


您可以犯的第一个错误是创建一个使用通用名称(如常量)调用的全局可访问类。这只不过是垃圾堆,你就失去了找出系统中哪个部分使用这些常量的所有能力。

相反,常量应该进入"拥有"它们的类中。是否有一个称为超时的常量?它可能会进入Communications()或Connection()类。每小时最大登录次数?进入用户()。等等。

另一种可能的用法是当运行时定义"常量",但不容易更改用户时,可以使用Java.Frasic文件。您可以将它们打包到.jar中,并使用类资源加载器引用它们。


这是正确的方法。

一般来说,常量不会保存在单独的"常量"类中,因为它们是不可发现的。如果常量与当前类相关,则将其保留在那里有助于下一个开发人员。


枚举呢?


我更喜欢使用getter而不是常量。这些getter可能返回常量值,例如public int getMaxConnections() {return 10;},但是任何需要该常量的东西都将经过getter。

一个好处是,如果您的程序超出了常量——您发现它需要可配置——您可以更改getter返回常量的方式。

另一个好处是,为了修改常量,您不必重新编译使用它的所有内容。当引用静态最终字段时,该常量的值将编译为引用它的任何字节码。


我同意使用接口不是一种可行的方法。避免这种模式甚至在布洛赫的有效Java中也有自己的项目(α18)。

Bloch反对常量接口模式的一个论点是,使用常量是一个实现细节,但是实现一个使用常量的接口会在导出的API中公开该实现细节。

public|private static final TYPE NAME = VALUE;模式是声明常量的好方法。就个人而言,我认为最好避免创建一个单独的类来存放所有常量,但除了个人偏好和风格之外,我从来没有看到过不这样做的原因。

如果常量可以很好地建模为枚举,请考虑1.5或更高版本中的枚举结构。

如果您使用的版本早于1.5,您仍然可以通过使用普通Java类来退出类型化枚举。(有关详细信息,请参阅此网站)。


基于上面的评论,我认为这是一种很好的方法,可以将老式的全局常量类(具有公共静态最终变量)以如下方式更改为类似枚举的等价类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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;
    }

}

所以我可以把它们称为:

1
Constants.StringConstant.DB_HOST


一个好的面向对象设计不需要许多公共可用的常量。大多数常量都应该封装在需要它们完成工作的类中。


对此有一定的意见要回答。首先,Java中的常量通常被声明为公共的、静态的和最终的。原因如下:

1
2
3
4
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

我从不简单地为常量访问器/对象使用接口,因为通常期望实现接口。这看起来不好笑吗:

1
String myConstant = IMyInterface.CONSTANTX;

相反,我会根据一些小的权衡选择几种不同的方法,因此这取决于您需要什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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

What is the best way to implement constants in Java?

Ok.

我们真正应该避免的一种方法是:使用接口定义常量。好的。

创建一个专门声明常量的接口实际上是最糟糕的事情:它破坏了接口设计的原因:定义方法契约。好的。

即使接口已经存在以满足特定的需求,声明其中的常量确实没有意义,因为常量不应该成为API的一部分,也不应该成为提供给客户机类的契约的一部分。好的。

为了简化,我们大致有4种有效的方法。好的。

使用static final String/Integer字段:好的。

  • 1)使用一个在内部声明常量的类,但不仅如此。
  • 1 variant)创建一个只用于声明常量的类。

使用Java 5 enum时:好的。

  • 2)在相关目的类(如嵌套类)中声明枚举。
  • 2 variant)将枚举创建为独立类(在其自己的类文件中定义)。

TLDR:哪种方法是最好的,在哪里定位常数?好的。

在大多数情况下,枚举方法可能比static final String/Integer方法更好,我个人认为只有在我们有充分理由不使用枚举的情况下,才应该使用static final String/Integer方法。关于我们应该在哪里声明常量值,我们的想法是搜索是否有一个单独的现有类拥有一个特定的、强大的、具有常量值的功能内聚性。如果我们找到这样一个类,我们应该用它作为常量保持器。否则,常量不应与任何特定类相关联。好的。

static final String/static final Integerenum的比较好的。

Enums的使用确实是一种需要严格考虑的方法。Enums比StringInteger常数场有很大的优势。它们设置了更强的编译约束。如果定义的方法将枚举作为参数,则只能传递在枚举类中定义的枚举值(或空)。使用字符串和整数,您可以用任何兼容类型的值替换它们,即使该值不是static final String/static final Integer字段中定义的常量,编译也会很好。好的。

例如,在类中定义为static final String字段的两个常量下:好的。

1
2
3
4
5
6
public class MyClass{

   public static final String ONE_CONSTANT ="value";
   public static final String ANOTHER_CONSTANT ="other value";
   . . .
}

这里是一个方法,它期望将这些常量中的一个作为参数:好的。

1
2
3
public void process(String constantExpected){
    ...    
}

您可以这样调用它:好的。

1
process(MyClass.ONE_CONSTANT);

或好的。

1
process(MyClass.ANOTHER_CONSTANT);

但是没有编译约束阻止您以这种方式调用它:好的。

1
process("a not defined constant value");

只有在运行时才有错误,并且只有在一次检查传输值时才有错误。好的。

对于枚举,不需要检查,因为客户端只能在枚举参数中传递枚举值。好的。

例如,这里有两个在枚举类中定义的值(即框外常量):好的。

1
2
3
4
5
6
7
8
9
10
11
public enum MyEnum {

    ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");

    private String value;

    MyEnum(String value) {
       this.value = value;
    }
         ...
}

这里有一个方法,它希望将这些枚举值之一作为参数:好的。

1
2
3
public void process(MyEnum myEnum){
    ...    
}

您可以这样调用它:好的。

1
process(MyEnum.ONE_CONSTANT);

或好的。

1
process(MyEnum.ANOTHER_CONSTANT);

但是编译永远不会允许您以这种方式调用它:好的。

1
process("a not defined constant value");

我们应该在哪里声明常量?好的。

如果您的应用程序包含一个单独的现有类,该类具有特定的强功能内聚性和常量值,那么1)和2)看起来更直观。一般来说,如果常量是在处理它们的主类中声明的,或者具有一个非常自然的名称来猜测我们将在其中找到它,那么它就可以简化常量的使用。好的。

例如,在JDK库中,指数和PI常量值在一个不仅声明常量声明(java.lang.Math的类中声明。好的。

1
2
3
4
5
6
   public final class Math {
          ...
       public static final double E = 2.7182818284590452354;
       public static final double PI = 3.14159265358979323846;
         ...
   }

使用数学函数的客户通常依赖于Math类。因此,他们可以很容易地找到常数,也可以记住以非常自然的方式定义EPI的位置。好的。

如果您的应用程序不包含一个现有类,该类与常量值(1个变量)和2个变量)具有非常具体和强大的功能内聚性,那么它的方式会更直观。一般来说,如果这些常量声明在一个处理它们的类中,而我们也有3或4个其他类处理它们的次数和处理它们的次数一样多,并且这些类中没有一个比其他类更自然地承载常量值,那么使用常量并不容易。在这里,定义一个只保存常量值的自定义类是有意义的。例如,在JDK库中,没有在特定类中声明java.util.concurrent.TimeUnit枚举,因为实际上没有一个而且只有一个JDK特定类看起来是最直观的类来保存它:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum TimeUnit {
    NANOSECONDS {
      .....
    },
    MICROSECONDS {
      .....
    },
    MILLISECONDS {
      .....
    },
    SECONDS {
      .....
    },
      .....
}

java.util.concurrent中声明的许多类使用它们:BlockingQueueArrayBlockingQueueCompletableFutureExecutorService……实际上,没有一个更适合保存枚举。好的。好啊。


单一的通用常量类是个坏主意。常量应该与它们在逻辑上最相关的类一起分组。

我建议您使用方法,而不是使用任何类型的变量(尤其是枚举)。创建一个与变量同名的方法,并让它返回您分配给该变量的值。现在,删除变量,并用对刚刚创建的方法的调用替换对它的所有引用。如果您认为常量是足够通用的,不需要创建类的实例就可以使用它,那么将常量方法设置为类方法。


任何类型的常量都可以通过创建类中的不可变属性来声明(该属性是带有final修饰符的成员变量)。通常还提供了staticpublic修饰语。

1
2
3
public class OfficePrinter {
    public static final String STATE ="Ready";  
}

有许多应用程序中常量的值表示从n元组(例如枚举)中选择的选项。在我们的示例中,我们可以选择定义一个枚举类型,该类型将限制可能分配的值(即改进的类型安全性):

1
2
3
4
public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}

fwiw,以秒为单位的超时值可能是一个配置设置(从属性文件或通过注入读取,如在Spring中),而不是一个常量。


有什么区别

1。

1
2
3
public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2。

1
2
3
4
public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

并使用在我们需要这个常数的地方。我认为两者都是一样的。


对于常量,枚举是更好的选择imho。下面是一个例子

公共类MyClass{

1
2
3
4
5
6
7
8
9
10
11
public enum myEnum {
    Option1("String1", 2),
    Option2("String2", 2)
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}

这是个坏习惯,而且很可怕引用乔舒亚·布洛赫的话,却不理解基本的零基础原教旨主义,这是一种令人讨厌的做法。好的。

我也没读过乔舒亚·布洛克的书,所以好的。

  • 他是个糟糕的程序员
  • 或者,到目前为止,我发现引用他的人(我猜约书亚是一个男孩的名字)只是用他的材料作为宗教脚本来证明他们的软件宗教放纵是正当的。

正如圣经原教旨主义一样,所有的圣经法则都可以概括为:好的。

  • 全心全意地爱这个基本的身份
  • 像爱自己一样爱你的邻居

同样,软件工程的原教旨主义也可以概括为好的。

  • 用你所有的编程能力和思想专注于零基础知识
  • 像你自己一样,为你的程序员同事的卓越贡献力量。

此外,在圣经的原教旨主义圈子中,有一个强有力而合理的推论。好的。

  • 第一次爱你自己。因为如果你不太爱自己,那么"爱你的邻居如同爱你自己"的概念就没有什么分量,因为"你有多爱你自己"是你爱别人的基准线。

同样地,如果你不尊重自己作为一个程序员,只是接受一些编程大师Nath的声明和预言而不质疑基本原理,那么你的引用和对Joshua Bloch(以及类似的)的依赖是毫无意义的。因此,您实际上不会尊重您的程序员同事。好的。

软件编程的基本规律好的。

  • 懒惰是一个好程序员的美德。
  • 你要使你的编程生活尽可能的简单,懒惰,因此尽可能的有效。
  • 你要让你的程序设计的结果和本质尽可能地简单、懒惰,从而对你的邻居程序员尽可能地有效,他们与你一起工作,并拾起你的程序设计本质。

接口模式常量是个坏习惯吗????

根据什么基本有效和负责任的法律,这个宗教法令是属于什么?好的。

只需阅读维基百科关于接口模式常量(https://en.wikipedia.org/wiki/constant_interface)的文章,以及它针对接口模式常量声明的愚蠢借口。好的。

  • 没有IDE?作为一个软件程序员,到底有谁不使用IDE?我们中的大多数人都是程序员,他们不愿意通过避免使用IDE来证明自己具有男子气概、唯美主义的生存主义。好的。

    • 另外-等待微函数编程的第二个支持者作为不需要IDE的方法。等待您阅读我关于数据模型规范化的解释。
  • 是否使用当前范围内未使用的变量污染命名空间?它可能是这种观点的支持者好的。

    • 不知道和需要数据模型规范化
  • 使用接口强制常量是对接口的滥用。这样的支持者有一个坏习惯好的。

    • 没有看到"常量"必须被视为契约。接口用于强制或预测对合同的遵从性。
  • 如果将来不可能将接口转换为实现的类,那就很困难了。哈…六羟甲基三聚氰胺六甲醚。。。????好的。

    • 为什么你要从事像你的持久生计这样的编程模式?噢,为什么要把自己投入到这样一个矛盾和糟糕的编程习惯中去呢?

无论借口是什么,当涉及到从根本上有效的软件工程去合法化或通常不鼓励使用接口常量时,都没有有效的理由。好的。

起草美国宪法的开国元勋们的初衷和精神状态是什么并不重要。我们可以对开国元勋们的初衷进行辩论,但我只关心美国宪法的书面声明。每个美国公民都有责任利用美国宪法中的书面文学原教旨主义,而不是不成文的创始意图。好的。

同样,我不关心Java平台和编程语言的创建者对接口的"原创性"意图。我关心的是Java规范提供的有效特性,我打算充分利用这些特性来帮助我完成负责软件编程的基本规律。我不在乎我是否被认为"违反了接口的意图"。我不在乎小鹅或布洛赫说的"使用Java的正确方式",除非他们说的话不违反我对有效履行基本原则的需要。好的。基础是数据模型规范化

不管数据模型是如何承载或传输的。如果您不理解数据模型规范化的需求和过程,那么您是否使用接口、枚举或whatevernots、关系或不使用SQL。好的。

我们必须首先定义和规范化一组流程的数据模型。当我们有一个一致的数据模型时,只有这样我们才能使用它的组件的过程流来定义功能行为,并且过程阻塞一个应用领域或领域。只有这样,我们才能定义每个功能流程的API。好的。

即使是EFCodd提出的数据规范化方面,现在也面临着严峻的挑战和严峻的挑战。例如,他关于1nf的声明被批评为模棱两可、不协调和过于简化,他的其他声明也被批评为模棱两可、不协调和过于简化,特别是在现代数据服务、回购技术和传输的出现中。在我看来,ef-codd语句应该被完全抛弃,并设计出一组新的更具数学意义的语句。好的。

ef-codd的一个显著缺陷和它与人类有效理解的不一致的原因是他相信人类可感知的多维可变维度数据可以通过一组零碎的二维映射有效地被感知。好的。数据规范化的基础

什么ef-codd没有表达。好的。

在每个相干数据模型中,这些是要实现的数据模型相干的顺序分级顺序。好的。

  • 数据实例的统一性和标识。
    • 设计每个数据组件的粒度,其中它们的粒度在一个级别上,在这个级别上可以唯一地标识和检索组件的每个实例。
    • 缺少实例别名。也就是说,不存在标识产生一个组件的多个实例的方法。
  • 缺少实例串扰。不存在使用组件的一个或多个其他实例来帮助标识组件的实例的必要性。
  • 数据组件/维度的统一性和标识。
    • 存在组件消除混叠。必须存在一个可以唯一标识组件/维度的定义。它是组件的主要定义;
    • 主要定义不会导致暴露不属于预期组件的子维度或成员组件;
  • 组件处理的唯一方法。对于一个组件,必须存在一个且只能存在一个这样的组件消除别名定义。
  • 存在一个且只有一个定义接口或契约,用于标识组件层次关系中的父组件。
  • 没有组件串音。不存在使用另一个组件的成员来帮助确定组件的身份的必要性。
    • 在这种父子关系中,父级的标识定义不能依赖于子级的成员组件集的一部分。父代标识的成员组件必须是完整的子代标识,而不必引用子代的任何或所有子代。
  • 抢占数据模型的双模或多模外观。
    • 当一个组件存在两个候选定义时,很明显有两个不同的数据模型混合在一起。这意味着在数据模型级别或字段级别上存在不一致性。
    • 一个应用领域必须一致地使用一个而且只能使用一个数据模型。
  • 检测和识别成分突变。除非你对大量的数据进行了统计成分分析,否则你可能看不到或看不到需要治疗的成分突变。
    • 数据模型的某些组成部分可能会周期性地或逐渐地发生变异。
    • 模式可以是成员旋转或换位旋转。
    • 成员旋转突变可能是组件之间子组件的不同交换。或者需要定义全新的组件。
    • 转置突变表现为维度成员突变为属性,反之亦然。
    • 每个突变周期必须被识别为一个不同的数据模式。
  • 对每个突变进行版本化。这样,当需要处理8年前的数据模型突变时,您就可以调出数据模型的早期版本。
  • 在服务间组件应用程序的字段或网格中,必须有且只有一个一致的数据模型,或者存在一种数据模型/版本识别自身的方法。好的。我们还在问是否可以使用接口常量?真正地?

    有一些数据规范化问题比这个平凡的问题更为重要。如果您不解决这些问题,那么您认为接口常量所导致的混乱相对来说就没有什么。齐尔奇好的。

    通过数据模型规范化,您可以将组件确定为变量、属性和契约接口常量。好的。

    然后,您可以确定哪些进入值注入、属性配置放置、接口、最终字符串等。好的。

    如果您必须使用这样一个借口来定位一个更容易根据接口常量指示的组件,这意味着您不习惯不执行数据模型规范化。好的。

    也许您希望将数据模型编译成VCS版本。您可以拉出一个明显可识别的数据模型版本。好的。

    接口中定义的值完全保证是不可变的。可分享。当您只需要一组常量时,为什么要从另一个类将一组最终字符串加载到您的类中??好的。

    那么为什么不发布一个数据模型契约呢?我是说,如果你能连贯地管理和规范它,为什么不呢?…好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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"
          }
        }
      }
    }

    现在,我可以通过以下方式引用我的应用程序的合同标签:好的。

    1
    2
    CustomerService.Label.Address.Street
    CustomerService.Label.Person.NameParts.Family

    这会混淆JAR文件的内容吗?作为Java程序员,我不关心JAR的结构。好的。

    这给OSGi驱动的运行时交换带来了复杂性?OSGi是一种非常有效的方法,可以让程序员继续保持他们的坏习惯。有比OSGi更好的选择。好的。

    或者为什么不呢?私有常量不会泄漏到已发布的合同中。所有私有常量都应分组到一个名为"constants"的私有接口中,因为我不想搜索常量,而且我太懒了,无法重复键入"private final string"。好的。

    1
    2
    3
    4
    5
    6
    7
    public class PurchaseRequest {
      private interface Constants{
        String INTERESTINGName ="Interesting Name";
        String OFFICIALLanguage ="Official Language"
        int MAXNames = 9;
      }
    }

    或许是这样:好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface PurchaseOrderConstants {
      public interface Properties{
        default String InterestingName(){
           return something();
        }
        String OFFICIALLanguage ="Official Language"
        int MAXNames = 9;
      }
    }

    接口常量唯一值得考虑的问题是何时实现接口。好的。

    这不是接口的"初衷"?就像我关心国父们制定美国宪法的"初衷",而不是最高法院如何解读美国宪法的书面信件????好的。

    毕竟,我生活在自由之地,野性之地,勇敢之家。勇敢,自由,狂野-使用界面。如果我的程序员同事拒绝使用高效和懒惰的编程方法,我是否有义务遵循黄金法则来降低编程效率以与他们的编程一致?也许我应该,但那不是一个理想的情况。好的。好啊。


    我比较喜欢static final,如果物品确实是可枚举的,我只使用enum


    为了更进一步,您可以将全局使用的常量放在一个接口中,这样它们就可以在系统范围内使用。例如。

    1
    2
    3
    public interface MyGlobalConstants {
        public static final int TIMEOUT_IN_SECS = 25;
    }

    但那就不要实施它。只需通过完全限定的类名在代码中直接引用它们。


    我使用static final声明常量,并使用全大写命名符号。我已经看到了很多现实生活中的实例,其中所有常量都聚集在一个接口中。一些帖子正确地称这是一个糟糕的实践,主要是因为这不是一个接口的作用。接口应该执行契约,而不应该是放置不相关常量的地方。如果常量语义不属于某个特定的类,那么将其组合到一个(通过私有构造函数)无法实例化的类中也可以。我总是在它最相关的类中放置一个常量,因为这很有意义,也很容易维护。

    枚举是表示一系列值的好选择,但是如果您存储的是独立常量,并强调绝对值(例如超时=100 ms),则可以使用static final方法。


    我同意大多数人所说的,在处理常量集合时最好使用枚举。但是,如果您在Android中编程,有一个更好的解决方案:intdef注释。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @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注释在一个简单的方法上优于Enums,因为它只是一个编译时标记,所以占用的空间要少得多。它不是类,也没有自动字符串转换属性。


    我不认为这个类与常量是相同的(除了大小写之外)。我至少会有一类"设置",或者"值",或者"常量",所有的常量都会存在。如果我有很多,我会将它们分组到逻辑常量类(用户设置、应用设置等)中。


    我这样做的方法之一是用常量值创建一个"全局"类,并在需要访问常量的类中执行静态导入。