2014-05-14 136 views
4

我想了解各种情况下类实例的初始化。
在JLS-7 12.5节中,没有提到最终实例变量是如何以及何时初始化的?有人能指出我了解在实例变量声明为final的情况下的行为吗?初始化“最终”实例变量

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 
+0

你能发布实际的代码吗? – njzk2

+3

此代码目前没有工作,您没有任何构造函数,因为'a'不是父类的名称。 'meth()'方法永远不会被调用,但它会创建一个输出。如果你清理代码,我们可能会更好地帮助你。 –

+0

已更正代码 – Pushparaj

回答

2

final int e = a; 

constant variableconstant expression。在调用

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

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

final int e = super.a; 

可变e不是常数可变,因为super.a不是simple name,因此,该值不能与将不被替换。

+0

“编译器可以用它的值来代替e的使用,30。”我在哪里可以找到JLS有关这个常量变量替换..这似乎是隐含的,但我希望看到,在JLS ..因为如果我们有这样的类子延伸父母{0} {0} {0} {0}最终int e = a; int b = a; System.out.println(“From Sub,e =”+ e +“,b =”+ b); }我们得到输出30,0,因为b不是最终的,因此不是常量变量,因此在编译时不能被替换。 – Pushparaj

+0

同样在JLS-7中“在运行时,静态字段是最终的并且用常量 表达式(§15.28)初始化(§12.4.2)。这也适用于接口中的这​​些字段 (§9.3 .1)这些字段是“常量”,即使通过不正确的程序(第13.4.9节), 也不会被观察到它们具有其默认初始值(§4.12.5) “..但他们没有提到比如最后的变量...... – Pushparaj

+1

@Pushparaj答案是关于字符串文字和字符串连接章节的一部分。在'Parent'构造函数完成后(参见字节码),在'Child'构造函数中实际初始化了字段'e' _is_,但是在包含常量表达式连接的字符串文字中,这些值在编译时按原样使用并且被使用。 –

1

码的第一片被给予输出如下

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

这是因为以下原因。

第一件事,当我们做new Child(),儿童类的constrcutor开始执行

但它的第一条语句是默认的超级因此它给父类constrctor通话

现在父类constrcutor有下面的代码

父(){ System.out.println(“From super Contsrutor”+ a); (); }

所以这里的父类调用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); 
    } 
} 
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类,它在调用before之前tructor。

现在,如果你可以从创作Child对象第一Parent级的输出看到的是加载到内存中,然后你叫meth方法内Parent构造将在这个时间打电话meth方法Child类,但Child的初始化块和Child的构造函数不叫这意味着此时b不是初始化为30而是int默认值0,与e变量的情况相同。