最终类变量的初始化之间的区别

时间:2014-06-11 10:08:29

标签: java class variables initialization final

我只是试着设置一个变量,告诉我超级构造函数已经完成而没有浪费我的代码。 所以我记得如何初始化类变量;在超级构造函数之后但在类构造函数之前。 但是如果你看一下这个例子,有一些奇怪的事情:

public class Init {

    public Init() {
        System.out.println("Init instance of " + this.getClass().getSimpleName());
        System.out.println("syso Init:");
        this.syso(false);
    }

    protected void syso(boolean childCall) {
        System.out.println("should not be printed because the method is overwitten");
    }

    public static class Child extends Init {

        private final boolean finalTrueA = true;
        private final boolean finalTrueB;
        private final boolean finalTrueC;

        private boolean nonFinalTrueA = true;
        private boolean nonFinalTrueB;
        private boolean nonFinalTrueC;

        {
            this.finalTrueB = true;
            this.nonFinalTrueB = true;
        }

        public Child() {
            super();
            this.finalTrueC = true;
            this.nonFinalTrueC = true;

            System.out.println("\n\nsyso Child:");
            this.syso(true);
        }

        @Override
        protected void syso(boolean childCall) {
            System.out.println("finalTrueA " + this.finalTrueA + " should be " + childCall);
            System.out.println("finalTrueB " + this.finalTrueB + " should be " + childCall);
            System.out.println("finalTrueC " + this.finalTrueC + " should be " + childCall);

            System.out.println();

            System.out.println("nonFinalTrueA " + this.nonFinalTrueA + " should be " + childCall);
            System.out.println("nonFinalTrueB " + this.nonFinalTrueB + " should be " + childCall);
            System.out.println("nonFinalTrueC " + this.nonFinalTrueC + " should be " + childCall);
        }
    }

    public static void main(String[] args) {
        @SuppressWarnings("unused")
        Child child = new Child();
    }

}

具有以下输出:

Init instance of Child
syso Init:
finalTrueA true should be false // <-- why??????????
finalTrueB false should be false
finalTrueC false should be false

nonFinalTrueA false should be false
nonFinalTrueB false should be false
nonFinalTrueC false should be false


syso Child:
finalTrueA true should be true
finalTrueB true should be true
finalTrueC true should be true

nonFinalTrueA true should be true
nonFinalTrueB true should be true
nonFinalTrueC true should be true

可以在eclipse输出以及使用javac运行类时看到此效果。 但是eclipse调试器在syso方法的超级构造函数调用中显示了 finalTrueA 的正确值。

所以我的问题:这个效果是否正确,不同的初始化会导致静态字段的不同行为,这是eclipse调试器的错误,或者这种行为是不正确的,这是java的错误??? / p>

2 个答案:

答案 0 :(得分:1)

立即分配了编译时常量且具有原语或final类型的每个String变量也是一个编译时常量,其值将在编译时内联 -time 在表达式上下文中使用时。这适用于所有变量,而不仅仅是static。请考虑以下(有效)代码:

public static void main(String[] args)
{
  final int zero=0, one=zero+1, two=one+one, three=two+one;
  switch(args.length)
  {
    case zero: System.out.println("no args"); break;
    case one: System.out.println("one arg"); break;
    case two: System.out.println("two args"); break;
    case three: System.out.println("three args");
  }
}

此处,局部变量zeroonetwothree是编译时常量,因此甚至可以作为switch case标签... < / p>

在你的情况下,this.finalTrueA的值在编译时内联,因此即使从超级构造函数调用时也是true

答案 1 :(得分:0)

应在编译期间分配所有final个变量。可以通过static initializerin the constructor或通过类本身。

请参阅jls

中的摘录
It is a compile-time error if a blank final (§4.12.4) class variable is not definitely
assigned (§16.8) by a static initializer (§8.7) of the class in which it is declared.

A blank final instance variable must be definitely assigned (§16.9) at the end of every
constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs

基于此,变量finalTrueA在编译时设置为true,这就是您看到true的原因。