【问题标题】:Implementing a class of "constants" initialized at application start not at compile time实现在应用程序启动时而不是在编译时初始化的“常量”类
【发布时间】:2014-12-30 14:53:01
【问题描述】:

我正在开发一个使用一大类常量的 Java 项目,例如:

public final class Settings {
    public static final int PORT_1 = 8888;
    public static final int PORT_2 = 8889;
    ...
}

现在,这些常量的某些值在编译时不再可用,因此我需要一种在应用程序启动时“初始化”它们的方法(例如,从 args[] 开始)。一旦初始化,就不应该改变它们。我对java不是很熟练,我该如何以可接受的方式做到这一点?

我曾想过使用单例与“一次性”设置方法之类的方法,如果多次调用它会引发异常,但它接缝太老套了...

【问题讨论】:

  • final 变量只能分配一次。您可以args[] 分配一次。
  • 这些常量是完美的,在 jvm 的生命周期内永远不会改变。你为什么要考虑使用 Singleton?
  • @MarounMaroun 如果我让它们不是静态的并且在我的主类中,我可以从 args[] 分配它们,但是如果它们在 Setting 类中,我该怎么做?我不能把它们留在那里,否则它甚至不会编译

标签: java singleton constants


【解决方案1】:

你可以像这样使用静态初始化器:

public final class Settings {
  public static final int PORT_1;
  public static final int PORT_2;
  ...

  static {
    // create the value for PORT_1:
    PORT_1 = ...;
    // create the value for PORT_2:
    PORT_2 = ...;
  }
}

静态初始化器在类加载期间执行。 PORT_1PORT_2 上的最终关键字保护它们在以后被更改。

【讨论】:

  • 这看起来很有希望,但我如何告诉静态初始化程序使用用户插入的值作为应用程序参数?
  • @flagg19 读取静态初始化块内的用户设置(我假设是文件、数据库记录、首选项节点集等)。
  • 我明白了...谢谢,但假设我将所有这些值作为命令行参数?我真的应该将它们写在文件或首选项上,以便能够在静态初始化程序中读取它们吗?这不是很常见的需求还是我在做一些奇怪的事情?
  • 这是一种常见的情况,但通常不会在命令行中指定用户设置。通常,用户通过用户界面设置它们,您的程序保存它们,然后在以后启动时,程序读取保存的信息。
【解决方案2】:

好吧,除非有大量常量,否则使用系统属性是一种方法。

private static final String CONSTANT1 = System.getProperty("my.system.property");
private static final int CONSTANT2 = Integer.valueOf(System.getProperty("my.system.property"));

系统属性在使用-D 标志启动应用程序时在命令行上传递。

如果变量太多,可以使用静态初始化器,其中可以读取包含属性的属性文件或类似文件:

public class Constants {
    private static final String CONSTANT1 = System.getProperty("my.system.property");
    private static final int CONSTANT2 = Integer.valueOf(System.getProperty("my.system.property"));
    private static final String CONSTANT3;
    private static final String CONSTANT4;

    static {
        try {
            final Properties props = new Properties();
            props.load(
                new FileInputStream(
                        System.getProperty("app.properties.url", "app.properties")));

            CONSTANT3 = props.getProperty("my.constant.3");
            CONSTANT4 = props.getProperty("my.constant.3");
        } catch (IOException e) {
            throw new IllegalStateException("Unable to initialize constants", e);
        }
    }
}

请注意,如果您使用一些外部框架,例如 Spring Framework 或类似框架,通常有一个内置机制。例如。 - Spring Framework 可以通过@Value 注解从属性文件中注入属性。

【讨论】:

  • 这会起作用,而且是最简单的解决方案,atm 我有大约 10 个常量需要以这种方式设置,但它们可能会增长到大约 20 个。这是否被认为是一种好习惯或至少可以接受? .jar 文件将由 bash 脚本启动,所以我不介意它是单行还是很大。
  • 这绝对是一种可以接受的方法。但是,常量的数量很多我相信其他方法更好。一种方法是使用静态初始化程序并从文件中读取数据(以便能够将常量外部化),就像我添加到答案中一样。
【解决方案3】:

在 Java 中没有简单的方法可以做到这一点。模拟这种情况的一种方法是使用返回内部类型的构建器(因此它可以编写私有字段)但内部类型只有 getter。

看到这个答案:https://stackoverflow.com/a/1953567/34088

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-13
    • 2011-09-02
    • 2014-02-18
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多