静态块java中的常量问题

时间:2016-04-13 13:55:38

标签: java exception-handling static

我有两个关于静态块和常量的问题,下面是代码。

  1. 常量(甚至简单的静态变量)不能直接从静态块引用。它给出错误说"在定义字段之前不能引用字段"。但是通过静态方法访问时可以。
  2. 如果我在静态块的捕获中为常量赋值,如下所述,则会给出错误说"最终字段NAME可能已经被分配了#34;。但是,如果在捕获它时会出现错误,说明"空白的最终字段NAME可能尚未初始化"。
  3. 我想知道为什么会这样?

    代码:

    public class TestStaticblock {
    
        static{
            try {
    //          NAME = dummyStringValue() + NAME_APPENDER; // Cannot reference a field before it is defined
    //          NAME = dummyStringValue() + getNameAppender(); // This is OK
    
                NAME = dummyStringValue();
            } catch (Exception e) {
                NAME = null; // The final field NAME may already have been assigned
            }
        }
    
        private static String dummyStringValue() throws Exception{
            return "dummy";
        }
    
        private static String getNameAppender() throws Exception{
            return NAME_APPENDER;
        }
    
        private static final String NAME; // If I comment Catch it says "The blank final field NAME may not have been initialized"
        private static  String NAME_APPENDER = "appender";
    
    }
    

3 个答案:

答案 0 :(得分:2)

也许这会对那些寻找类似事物的人有所帮助。

Java有一个鲜为人知的特性(在Java专家Throwing Exceptions from Fields中讨论过),如果你想初始化一个final 实例变量(即 NOT a static)方法调用的结果抛出异常然后您可以通过添加抛出异常的构造函数来避免明显的错误。 请注意,此解决方案仅适用于非静态(而不是您正在观察的内容)。

public class TestStaticblock {

    private final String NAME = dummyStringValue();

    // Adding this removes the "unreported Exception" above.
    public TestStaticblock() throws Exception {
    }

    private static String dummyStringValue() throws Exception {
        return "dummy";
    }
}

答案 1 :(得分:2)

在分配之前,您不能在静态块中使用static final字段,但只需调用方法即可访问它。

例如,此代码打印null FOO

public class Main {

    static final String FOO;

    static {
        foo();
        FOO = "FOOFOO".substring(0, 3);
        foo();
    }

    static void foo() {
        System.out.println(FOO);
    }

    public static void main(String[] args) {}
}

这无疑是奇怪的,但我想这会使语言变得更加复杂,以至于无法做到这一点。

至于你的第二个问题,这不会编译。

static{
    try {
        NAME = dummyStringValue();
    } catch (Exception e) {
        NAME = null; // The final field NAME may already have been assigned
    }
}

这也很奇怪。如果抛出异常,则只能在方法dummyStringValue()内发生。由于您无法为方法内的final字段分配值,因此NAME变量已完全无法在catch块中分配。因此,没有可能的代码路径,其中未分配NAME。你认为它应该以与

相同的方式工作
static{
    if (someCondition()) {
        NAME = dummyStringValue();
    } else {
        NAME = null;
    }
}
编译好的

我想原因再一次是它会让语言变得更加复杂。允许它没有什么好处,因为您可以使用其他答案中指示的方法或temp变量。例外情况比if语句更复杂 - 它们的行为几乎就像goto。 @ElliottFrisch在评论中提出了一个很好的观点。这样的事情怎么样:

static{
    try {
        NAME1 = dummyStringValue1();
        NAME2 = dummyStringValue2();
    } catch (Exception e) {
        // Has NAME1 been assigned here?
    }
}

答案 2 :(得分:1)

我强烈的个人偏好是使用方法而不是初始化单个变量的静态初始化块:

private static final String NAME = getName();

private static String getName() {
  try {
    return something();
  } catch (Exception e) {
    return null;
  }
}
  1. 你不会遇到类似你所描述的问题。
  2. 您只能计算一个字段值,因此您不会想要将大量内容放入同一个块中。
  3. 您可以重新调用一种方法来测试它。