class Fu
{
int num = 40;
void show()
{
System.out.println("show Fu");
}
}
class Zi extends Fu
{
int num = 20;
void show()
{
System.out.println("show Zi");
}
void method()
{
System.out.println("method Zi");
}
}
class Text
{
public static void main(String[] args)
{
Fu fu = new Zi();
System.out.println(fu.num);
fu.show();
fu.method();
}
}
1、首先判断方法区里面的class文件区有多少个class文件,我这里有Fu.class,Zi.class,Text.class。
2、静态随着类的加载而加载,然后再判断方法区里面的静态方法区里面有什么方法,我这里只有main方法
3、然后main方法进栈,处于高地址(也就是最下面)
4、main方法里面有一个引用,名为fu的Fu变量,但开辟的是Zi的空间,于是堆内存就开辟了一个new Zi()的空间
5、我们可以这样想,其实 new Zi() 空间里面包含着两个空间,一个空间用this来标记,一个用super来标记;
6、标记着子类空间的用this来表示,标记父类空间的用super来表示。
7、子继承类的时候,是先对父类进行初始化,开始父类声明了个值为40的num变量(在堆中产生),父类里面又有个show(),把方法放在Fu类的方法区中,Fu类方法区的地址给了super,从而super可以访问Fu类方法区的方法,super空间才初始化完毕。
8、这时候,super空间与Fu类方法区有了一定的关联,但没有去访问。
9、父类初始化完毕,就去初始化子类
10、首先Zi类有个值为20的num变量(在堆中产生),然后再加载show方法和method(在Zi类方法区中产生)。
11、然后Zi类方法区的地址给了this,从而this可以访问Zi类方法区的方法,this空间也就初始化完成。
12、这时候,this空间与Zi类方法区有了一定的关联,但也同样没有去访问。
13、new Zi()空间初始化完毕之后,把地址给了fu的Fu类变量,然后fu也就指向new Zi ()。
14、然后补充一点:成员变量仅仅是该事物的外在特征描述,而成员方法是该事物的功能描述(内在特征描述)。
15、所以,当fu.num执行的时候,调用的是该类的外在特征描述,fu是代表父类的,所以也就是调用super空间的num;
外在特征的意思也就是,你本来是哪个类的对象,就调用哪个类的成员变量。
16、也所以,当fu.show()执行的时候,虚拟机会看看Fu类方法区中是否有show(),如果有,就看看有没被重写,没有被重写,就执行Fu方法区的show();如果有被重写,就调用子类的show()。如果Fu类中没有show(),就算子类有show(),编译也报错,更谈不上执行。
17、遇到多态的时候,简单总结一句话:编译看左边,运行看右边。