【问题标题】:Initializing public static final variables in constructor在构造函数中初始化公共静态最终变量
【发布时间】:2013-01-03 15:45:04
【问题描述】:

我正在尝试为我的应用程序创建一个 Version 类,该类将在加载时从清单中读取版本号,然后只需在其他地方需要它时引用例如 Version.MAJOR 等。但是,我在这样做时遇到了问题。这是我当前的代码:

 public class Version {

    public static final int APPCODE;
    public static final int MAJOR;
    public static final int MINOR;
    public static final char RELEASE;
    public static final int BUILD;

    static {

        try {
            Class clazz = Version.class;
            String className = clazz.getSimpleName() + ".class";
            String classPath = clazz.getResource(className).toString();
            if (classPath.startsWith("jar")) {
                String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF";
                Manifest manifest = new Manifest(new URL(manifestPath).openStream());
                Attributes attr = manifest.getMainAttributes();
                APPCODE = Integer.parseInt(attr.getValue("APPCODE"));
                MAJOR = Integer.parseInt(attr.getValue("MAJOR"));
                MINOR = Integer.parseInt(attr.getValue("MINOR"));
                RELEASE = attr.getValue("RELEASE").charAt(0);
                BUILD = Integer.parseInt(attr.getValue("BUILD"));
            }
        } catch (IOException e) {
            System.exit(9001);
        }
    }
}

它不会编译,因为 static final 变量可能没有被初始化(例如,如果加载了错误的清单或加载它时出现异常),我无法弄清楚执行此操作的正确程序是什么.

阅读this 的问题让我对不使用public static final 有了一些了解。我是否应该将 public static 与 getter 方法一起使用?

【问题讨论】:

    标签: java initialization constants manifest static-classes


    【解决方案1】:

    如果您确保始终只为 final 字段分配一次,编译器会很高兴:

    public class Version {
    
        public static final int APPCODE;
        public static final int MAJOR;
        public static final int MINOR;
        public static final char RELEASE;
        public static final int BUILD;
    
        static {
            int appcode = 0;
            int major = 0;
            int minor = 0;
            char release = 0;
            int build = 0;
            try {
                Class clazz = Version.class;
                String className = clazz.getSimpleName() + ".class";
                String classPath = clazz.getResource(className).toString();
                if (classPath.startsWith("jar")) {
                    String manifestPath = classPath.substring(0,
                            classPath.lastIndexOf("!") + 1)
                            + "/META-INF/MANIFEST.MF";
                    Manifest manifest = new Manifest(
                            new URL(manifestPath).openStream());
                    Attributes attr = manifest.getMainAttributes();
                    appcode = Integer.parseInt(attr.getValue("APPCODE"));
                    major = Integer.parseInt(attr.getValue("MAJOR"));
                    minor = Integer.parseInt(attr.getValue("MINOR"));
                    release = attr.getValue("RELEASE").charAt(0);
                    build = Integer.parseInt(attr.getValue("BUILD"));
                }
            } catch (IOException e) {
                System.exit(9001);
            }
            APPCODE = appcode;
            MAJOR = major;
            MINOR = minor;
            RELEASE = release;
            BUILD = build;
        }
    }
    

    【讨论】:

    • +1,用于说明如何通过覆盖所有执行路径来初始化最终字段。
    【解决方案2】:

    我愿意:

    • 删除最后的修饰符
    • 将可见性从公共降低到私人。
    • 为所需字段提供(静态)getter

    【讨论】:

      【解决方案3】:

      如果您使用public final 字段,则必须分配默认值,因为它们是常量。将可见性更改为私有并删除 final 修饰符并提供 getter/setter。这应该是解决您的问题的最佳方式。

      【讨论】:

        【解决方案4】:

        您可以从 Version 类中删除处理读取清单的代码块并将其放入单独的类中 - 例如 (ManifestReader) - 并在构造函数中直接使用实际值初始化版本实例。

        我会将“public static final”更改为“private final”(不是静态的),因为如果您有多个 Version 类实例,则所有实例都必须有自己的应用代码、主要次要等!!

        除了提供 getter() 来访问私有 final 字段!

        【讨论】:

          猜你喜欢
          • 2014-08-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多