首页 > 代码库 > 关于子类实例化和初始化的不解与猜想

关于子类实例化和初始化的不解与猜想

首先来看看下面这段代码:

public class Base {    private int i=5;    public Base(){        System.out.println("I come from "+this.getClass()+"  i="+this.i);        this.display();    }    public int getI(){        return i;    }    public void display(){        System.out.println(this.i);    }}public class Sub extends Base {    private int i=22;    public Sub(){        i=222;    }    public void display(){        System.out.println("I come from "+this.getClass()+" i="+this.i);    }}public class Test {    public static void main(String[] args) {        Sub sub=new Sub();        System.out.println(sub.getI());    }}

打印结果为:

技术分享

下面我们来分析一下:

在main函数中首先执行

Sub sub=new Sub();

这行代码。而这行代码须分解为两步:

step1:执行new关键字,在执行这个关键字的时候,有一个疑问:new出来的对象中是否包含了父类中的所有变量(包括私有变量);

step2:执行new后面的括号即初始化对象。从Java核心技术卷一P131种可知初始化数据的步骤为:

1、所有数据被初始化为默认值;

2、按照类声明中出现的次序,依次执行所有域的初始化语句和初始化块;

3、如果构造器第一行调用了第二个构造器,则执行第二个构造器主体;

4、执行这个构造器的主体。

我相信这绝对是一个非常简化版的执行过程了。因为作者这里根本没有提到何时,调用父类的构造器。

那我们现在就来细细分析这个初始化的过程(其实在这篇文章中也分析过了,只是也不是很完整)。

为例更清晰的看看初始化的过程我们使用javap工具看看一个简单的类的字节码:

类代码:

    public class SimpleClass {    {        i=6;    }    private int i=0;    public SimpleClass(){        i=5;    }}
    字节码为:

技术分享

这下很清楚了。当对子类Sub初始化时,会首先调用其父类的构造函数,在这时子类Sub只有变量的声明,没有进行任何的赋值操作。jvm开始初始化父类Base:由上图可知,变量定义时赋值和初始化块中赋值在构造器中赋值之前进行。所以首先jvm执行Base中的i=5;此时Base中的被初始化为5了。然后执行构造函数中的语句(请分清构造器中的语句和构造器中的字节码)。接下来的执行见这篇文章。

现在问题是,在Sub初始化进行完之后,Sub包含了父类的那些变量?是不是包含了父类中的所有变量。如果不是(在书上看到是继承了父类非私有的变量),那么执行main函数的这条语句:

    System.out.println(sub.getI());

为什么会打印出5呢?因为sub对象中的i变量的值现在为222啊。

注:在李刚老师的《Java程序员基本功》书中看到,子类继承父类的非私有方法,只是将方法放进了自类中,该方法和该子类中其他方法的唯一区别就是多了一个super的标签。那么是不是就可以得出Sub子类中也把父类中的私有变量放到了自己的内存中了,只是我们无法访问而已。

记下疑点,以便慢慢解决……也希望大神们多多指点……

关于子类实例化和初始化的不解与猜想