当前位置:编程学习 > JAVA >>

关于Java构造函数的问题

class Base {
// 定义了一个名为i的实例变量
private int i = 2;

public Base() {
this.display();
}

public void display() {
System.out.println(i);
}
}

// 继承Base的Derived子类
class Derived extends Base {
// 定义了一个名为i的实例变量
private int i = 22;

// 构造器,将实例变量i初始化为222
public Derived() {
i = 222;
}

public void display() {
System.out.println(i);
}
}

public class Test {
public static void main(String[] args) {
// 创建Derived的构造器创建实例
new Derived();
}
}


运行结果是:0
求大牛解释一下原理。 --------------------编程问答-------------------- 同样的问题:http://bbs.csdn.net/topics/390256394 --------------------编程问答-------------------- 为毛最近都是这个问题?? --------------------编程问答-------------------- package test;

class Base {
    // 定义了一个名为i的实例变量
    private int i = 2;
 
    public Base() {
     System.out.println("Base中:"+i);
        this.display();
    }
 
    public void display() {
     System.out.println("Base中dis:"+i);
        System.out.println("我被多态了啊"+i);
    }
}
 
// 继承Base的Derived子类
class Derived extends Base {
    // 定义了一个名为i的实例变量
    private int i = 22;
 
    // 构造器,将实例变量i初始化为222
    public Derived() {
     System.out.println("Derived中:"+i);
        i = 222;
    }
 
    public void display() {
     System.out.println("Derived中dis:"+i);
        System.out.println("是我吗?"+i);
    }
}
 
public class Test {
    public static void main(String[] args) {
        // 创建Derived的构造器创建实例
        new Derived();
    }
}

运行结果是:
Base中:2
Derived中dis:0
是我吗?0
Derived中:22
加了几个输出会好看一点
我的理解是 new Derived();时候会递归调用父类构造方法,父类的构造方法又调用了子类的display()方法,这时候的i还是0吧,不很清楚为什么是0,大神指点吧...共同学习,输出的就是子类的那个display()方法的i
debug的时候出现了两个i,一个是属性的一个等于0的就看到这些了.... --------------------编程问答-------------------- new Derived();
此时,程序是这样走的:
1.进入Derived的构造方法:

public Derived() {
super();//这里隐含一个调用父类构造的语句。
i = 222;
}

2.通过super()方法进入Base类的构造方法:

public Base() {
this.display();//因为多态的原故,这句会调用子类覆写的方法
}

3.调用Derived类的display()方法:

public void display() {
System.out.println(i);//此时,变量i还未被赋值,默认初始值是0,因此输出0
}

4.第三步执行完后,再继续执行Derived构造方法里的下一句:

i = 222;//虽然变量i被赋值了,可是输出语句已经完成了。

5.程序执行完毕.

--------------------编程问答-------------------- 类的加载顺序:父类静态块、子类静态块、父类成员、父类构造函数、子类成员、子类构造函数。

如果父类构造函数中调用了已被子类重写的方法,则会进入子类重写的方法体内执行,如果该方法体中有引用子类的成员变量,由于子类成员还未初始化,所以会取其数据类型的默认值,此处i取0。

修改方法是,使子类初始化的方法签名与父类不同,或者直接写入子类的构造函数中。 --------------------编程问答-------------------- 其实这种例子最好还是自己试一下,多测试一下要比听别人讲的更明白。
我刚开始也做错了,后来自己更改不同的条件测试了7,8次吧。也就懂了。
首先,加上
System.out.println("derived display:"+i);
System.out.println("base display:"+i);
输出的是derived display:0,知道调用的是子类的方法。父类的方法被子类重写了。
然后
private int k=22;
public Derived(){
k=222;
}
public void display(){
System.out.println("derived display:"+i);
}
把Derived的i改成k,这时候输出i报错,也就说明其实没有i这个量。如果非要输出,只能输出0或者报错。

然后再把Base的i改成Public,这时候输出2。
这时候就说明是这道题做的功能实际上就是把子类的display方法代替了父类的那个display方法。
剩下的就容易理解了吧? --------------------编程问答-------------------- --------------------编程问答-------------------- class Base {
    // 定义了一个名为i的实例变量
   private  int i = 2;
 
    public Base()
    {
    System.out.println("父类的构造方法");
        this.display();
    }
 
    public void display() 
    { 
    System.out.println("父类的具体方法");
        System.out.println(i);
    }
}
 
// 继承Base的Derived子类
class Derived extends Base 
{
    // 定义了一个名为i的实例变量
    private int i = 22;
 
    // 构造器,将实例变量i初始化为222
    public Derived() 
    {
    System.out.println("子类的构造方法");
        i = 222;
    }
 
    public void display() 
    {
    System.out.println("子类的具体方法");
        System.out.println(i);
    }
}
 
public class Test12
{
    public static void main(String[] args)
    {
        // 创建Derived的构造器创建实例
        new Derived();
    }
}
Derived继承了Base类,因此在new Derived();实例化的过程中,通过new关键字调用无参的构造方法(),Derived继承了Base类,Derived类先加载在JVM上,然后实例化生成对象,通过这个对象,会先调用父类的无参构造方法,然后再执行调用子类的构造方法 --------------------编程问答-------------------- 简单地说,creation of instace of class 的时候,首先会初始化父类及其该类的成员变量(注意此时是赋予“默认初始值”),
然后初始化 参数列表中的变量(如果有),然后才执行其他语句。 --------------------编程问答--------------------
引用 9 楼 king769147 的回复:
简单地说,creation of instace of class 的时候,首先会初始化父类及其该类的成员变量(注意此时是赋予“默认初始值”),
然后初始化 参数列表中的变量(如果有),然后才执行其他语句。

   总之,不能理解为一new instance of class 的时候,就执行里面的语句。
  --------------------编程问答-------------------- 5楼正解。
这是一个典型的有继承关系的类的初始化顺序问题。

原理其实楼上有几位已经说得比较清楚了,下面我们来就题论题一下:

首先从main方法开始,new Derived()就是要new一个Derived的对象,那么根据对象初始化的顺序,
初始化子类Derived之前必须要初始化父类Base,那么由于在调用构造函数之前,成员变量是先于构造函数初始化的,这个时候Base里面的i已经有值了,是2。

在Base构造函数里面, 只有一句:this.display(), 这个方法在Base的子类Derived也定义了,并且此次初始 化是由子类Derived发起的,所以实际上这个方法调用的是Derived里面定义的display,而不是Base自己的display(所以输出不是2)。
而这个时候子类Derived还没有进行构造,因为此时父类Base才正在构造之中,所以子类Derived中的i还是0,而display正好打印出的是子类Derived的i,所以最后的输出是0.

不知道能解释的清楚楼主的问题么?  --------------------编程问答-------------------- 呵呵,回答的很好 --------------------编程问答-------------------- 除 --------------------编程问答--------------------
正解啊!
引用 4 楼 diypyh 的回复:
new Derived();
此时,程序是这样走的:
1.进入Derived的构造方法:
Java code12345public Derived() {    super();//这里隐含一个调用父类构造的语句。    i = 222;}
2.通过super()方法进入Base类的构造方法:
Java code1234public Base() {    th……
--------------------编程问答-------------------- 楼主在和我们开玩笑吧!
我实测了一下,输出结果是输出2!
1。《java核心技术卷1-基础知识》中说在使用new关键字实例化对象时,类的域(类的成员)会先于构造器被实例化。我实测了下,父类和子类的域会被几乎同时实例化,域实例化后的值是默认值。
2.我实测了下,代码中对类的域的赋值语句会在构造器启动之后,但是在开始执行方法块中的第一条语句之前执行。
3.子类的构造器在启动之后会先启动父类的构造器。(我知道“启动”这个词可能不够专业,但是我也不知道怎么描述。看的人懂就好。)
4.this关键字是指向实例的引用。
上面四点就可以解释这个测试类的输出结果了。 --------------------编程问答-------------------- 结果根本就不是0,结果是2
类的成员先于构造器被实例化,但值是默认值,在构造器被实例化后,成员被赋值,赋值之后,开始执行构造器。。。 --------------------编程问答-------------------- 15,16楼的,我想问下你们真的试了吗?还是在这胡言乱语,扰乱视听。结果就是0,本人亲试。 --------------------编程问答-------------------- 在构造方法里调用可被override的方法是非常sb的做法,
补充:Java ,  Java SE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,