java这道基础题为什么是这样的结果 谁能给讲讲?

给了不少分呢 详细讲讲
public class Dervied extends Base {

private String name = "dervied";

public Dervied() {
tellName();
printName();
}

public void tellName() {
System.out.println("Dervied tell name: " + name);
}

public void printName() {
System.out.println("Dervied print name: " + name);
}

public static void main(String[] args){

new Dervied();
}
}

class Base {

private String name = "base";

public Base() {
tellName();
printName();
}

public void tellName() {
System.out.println("Base tell name: " + name);
}

public void printName() {
System.out.println("Base print name: " + name);
}
}
运行结果是:

Dervied tell name: null
Dervied print name: null
Dervied tell name: dervied
Dervied print name: dervied

后两行还好说
前两行虽说子类重写了父类的方法 但是先执行的是父类的方法啊 而且前两行为什么是null

这道题很好,也相当基础而且很绕人。

1,首先先说一下父类与子类方法覆写(overrider)相关的概念,覆写在java中主要是通过方法表来完成,java中每个类型(Class)中都存在一个方法表,其中存放java类型的实例方法(public/protected),static方法属于静态方法,和类型相关,不属于javad实例方法。private和default属于私有方法,private/default修饰的方法不进入类型的方法表。

2,接下来说一下<clinit>和<init>方法,其中<clinit>称为类初始化方法,<init>称为对象实例化方法,该问题就与<init>方法息息相关。

<clinit>方法:

Java在进行对象创建时首先进行类型加载,如果Class类型存在父类型,则需要先加载父类完成以后再加载子类型。并且对static变量进行初始化操作,对static变量或者static代码块初始化的逻辑就封装在<clinit>方法中。

Java类型初始化过程中对static变量的初始化操作依赖与对static变量的赋值语句的前后关系,static语句块与static变量声明存在位置关系,java编译器与static变量的赋值位置有关。

<init>方法:

Java对象在进行实例化时,首先会进行父类的实例化操作,然后再进行子类的实例化操作。该部分操作封装在<init>方法中,并且子类的<init>方法中会首先对父类<init>方法的调用。

Java对象实例化过程中对实例域的初始化赋值操作全部在<init>方法中进行,<init>方法显式的调用父类的<init>方法,实例域的声明语句以及实例初始化语句块存在位置关系,<init>方法以构造方法作为结束。

--------------------------------------------------------------------------------------------------------------------

接下来回到这道题上来,启动java虚拟机:

第一步:加载应用用到的类,加载顺序为Base-->Dervied,这里涉及到<clinit>方法的调用,但是当前类型中没有static域或者是static{},所以<clinit>方法不再讨论。

第二步:对象实例化操作,首先我们new Dervied();,这样就触发对Dervied.<init>的调用,但是根据以上知识(“并且子类的<init>方法中会首先对父类<init>方法的调用”)我们可以知道,Dervied.<init>首先会调用到Base.<init>方法,所以现在我们调用的方法是Base.<init>,Base.<init>方法中,首先是对name域(父类Base)进行初始化,然后调用tellName()方法,因为子类以及覆写了tellName()方法,所以tellName方法实际调用为Dervied.tellName()方法,tellName方法要打印name域(子类Dervied)的值,但是当前Dervied对象中的name域还没有被初始化,所以打印出来的值为null。printName()方法执行与tellName()方法一致。

第三步:Base.<init>方法返回到Dervied.<init>方法中,紧接着对name域(子类Dervied)进行初始化操作,然后调用子类Dervied的tellName方法和printName方法,name域(子类Dervied)已经初始化完成,所以能正确打印出来。

--------------------------------------------------------------------------------------------------------------------

当前图片为父类<init>()方法的执行!其中name域(Dervied类)未初始化;


当前图片为子类<init>()方法的执行!其中name域(Dervied类)已初始化;


PS:另外当前问题也涉及到java对象的内存布局,其中Dervied对象还有两个name域,其中一个是从父类继承过来的,一个是自己类型私有的。

温馨提示:答案为网友推荐,仅供参考
第1个回答  2014-12-22

创建子类对象时,若未显式调用父类构造函数,系统隐式调用super()方法,这时候new Drived(),会跳转到Base();然后初始化name属性为base,接着调用tellName()方法,此时调用的对象(this)为Drived对象!所以又直接跳转到Drived类执行tellName方法,此时Drived类的name属性尚未赋值,所以输出Dervied tell name: null接下来同理输出Dervied print name: null,然后执行Drived类的构造方法,初始化name属性为drived,所以输出Dervied tell name: dervied和Dervied print name: dervied。

关键在于弄清楚调用方法的对象是谁!

new Drived()会跳转到Base(),但是此时this为Drived对象!

 public Base() {
        tellName();//相当于this.tellName()
        printName();//相当于this.tellName()
    }
    public Dervied() {
        tellName();//相当于this.tellName()
        printName();//相当于this.tellName()
    }

第2个回答  2014-12-22
执行main方法时,执行Derived类的实例化方法也就是无参构造器方法。因为Derived继承与Base,所以在执行构造器是隐藏执行父类的无参构造器,执行Base类无参构造器中的tellName和printName方法,因为这两个方法被Derived重写了,所以执行Derived类中的tellName和printName方法,但此时name属性还没被初始化,所以输出的是null,下面两行输出的就是Derived类本身的方法,此时name属性被初始化,所以得到了你的答案
第3个回答  2014-12-22
问题出在构造函数的地方,对于java中的extends,每个子类构造方法的第一条语句都是隐含的调用super,而且如果父类没有这种形式的构造函数就会报错。
你可以如下修改进行调试
public Dervied() {
tellName();
System.out.println("a");
printName();
}

public Base() {
tellName();
System.out.pritnln("b");
printName();
}
运行的结果将会是
Dervied tell name: null
b
Dervied print name: null
Dervied tell name: dervied
a
Dervied print name: dervied本回答被网友采纳
第4个回答  2014-12-22
Dervied extends Base 继承

Dervied复写两个方法 所以印出来的都一样!!
Dervied.class
Base.class
两个方法是一样的所以内容被复写了!!!
这样你知道了吗???
相似回答