4

我想了解各种情况下类实例的初始化。
在 JLS-7 第 12.5 节中,没有提到如何以及何时初始化最终实例变量?如果实例变量声明为最终变量,我可以参考一点来理解行为吗?

   public class Test {

        public static void main(String args[]){

            Child  c1 = new Child();
        }
    }

    class Parent{
        final int a =30;
        Parent(){
            System.out.println("From super Contsrutor "+a);
            meth();
        }
        void meth(){
             System.out.println("From super");
        }
    }

    class Child extends Parent{
         final  int e=super.a;
         int b=30;
        void meth(){
            System.out.println("From Sub e=" +e+", b="+b);
        }
    }

给出如下输出

From super Contsrutor 30
From Sub e=0,b=0

然而

public class Test {

    public static void main(String args[]){

        Child  c1 = new Child();
    }
}

class Parent{
    final int a =30;
    Parent(){
        System.out.println("From super Contsrutor "+a);
        meth();
    }
    void meth(){
         System.out.println("From super");
    }
}

class Child extends Parent{
     final  int e=a;
    void meth(){
        System.out.println("From Sub " +e);
    }
}

将输出作为

From super Contsrutor 30
From Sub 30
4

3 回答 3

2

final int e = a;

是一个常量变量,一个常量表达式。在调用中

System.out.println("From Sub e=" +e+", b="+b);

编译器可以e用它的值替换使用,30.

final int e = super.a;

该变量e不是一个常量变量,因为super.a它不是一个简单的名称,因此该值不能也不会被替换。

于 2014-05-14T18:15:12.183 回答
1

第一段代码给出如下输出

From super Contsrutor 30
From Sub e=0,b=0

这是因为以下原因。

当我们做的第一件事时new Child(),子类的构造函数开始执行

但它的第一条语句默认是超级的,所以它调用了父类构造函数

现在父类构造器具有以下代码

Parent(){ System.out.println("来自超级Contsrutor "+a); 方法();}

所以这里父类调用 meth() 方法,它的调用者实际上是子类子对象的对象,所以它调用子类 meth() 方法。

现在,当它从超级构造函数调用子类 meth() 方法时,实际上子对象尚未创建,因此其变量尚未初始化,但我们正在打印 a 和 b 的值。

所以在子构造函数执行完成后,b 在被分配之前得到 0。

因此,像下面这样更改您的第一段代码将提供所需的输出,即将 meth() 调用放在子构造函数中,而不是放在父构造函数上。

package com.kb.finalVariables;

public class Test {

    public static void main(String args[]){

        Child  c1 = new Child();
    }
}

class Parent{
    final int a =30;
    Parent(){
        System.out.println("From super Contsrutor "+a);
       // meth();
    }
    void meth(){
         System.out.println("From super");
    }
}

class Child extends Parent{

     final  int e=super.a;
     int b=30;
     public Child() {
        meth();
    }
    void meth(){
        System.out.println("From Sub e=" +e+", b="+b);
    }
}
于 2014-05-14T18:17:37.823 回答
1

让我们找出程序的流程,我为它编写了以下代码:

package com.test;

public class Test {

    public static void main(String args[]) {
        Child c1 = new Child();
    }
}

class Parent {
    final int a = 30;
    static int count = 0;
    {
        System.out.println("Parent initialization block " + ++count);
    }
    Parent() {
        System.out.println("Parent constructor " + ++count);
        // System.out.println("From super Contsrutor " + a);
        meth();
    }
    void meth() {
        // System.out.println("From super");
        System.out.println("Parent meth method " + ++count);
    }
}

class Child extends Parent {
    final int e = super.a;
    int b = 30;
    {
        System.out.println("Child initialization block " + ++count);
    }
    public Child() {
        System.out.println("Child constructor " + ++count);
    }
    void meth() {
        System.out.println("Child meth method " + ++count);
        // System.out.println("From Sub e=" + e + ", b=" + b);
    }
}

输出:

Parent initialization block 1
Parent constructor 2
Child meth method 3
Child initialization block 4
Child constructor 5

首先记住我已经为和类编写了初始化块,它在构造函数之前被调用。ParentChild

现在,如果您可以从创建Child对象的输出中看到第一个Parent类被加载到内存中,那么您已经methParent构造函数中调用了方法,该方法将调用类meth的方法,Child但是此时初始化块和构造函数没有被调用,这意味着此时 b未初始化为 30 而是默认值,与变量相同的情况。ChildChildint0e

于 2014-05-14T18:39:09.757 回答