JVM装载类的顺序
这几天看了下j2se基础,看到这个题目
class B {private int radius = 10;public void draw() { System.out.println("B.draw(), radius = " + radius);}public B() { System.out.println("B constructor"); draw();}}public class A extends B {private int radius = 1;public void draw() { System.out.println("A.draw(), radius = " + radius);}public A(int radius) { this.radius = radius; System.out.println("A constructor");}public static void main(String[] args) { A a = new A(5);}}结果是B constructorA.draw(), radius = 0A constructor
?首先是JVM装载类,如果有基类,则先装载基类,直到继承体系的根--Object,在装载类的时候会初始化所有static定义的成员变量;如果碰到有通过new来实例化的代码,则先为该类分配内存空间,所有的对象成员变量都赋予初值(所有基础数据类型都是赋值为0,对象类型都是null),然后执行构造方法,同样,会根据继承体系从根开始调用构造方法,调用每个类的构造方法时都会生成一个实例,会执行成员变量的初始化操作。
这里:当执行到A的构造方法时
public A(int radius) {this.radius = radius;System.out.println("A constructor");}
?先执行父类B的构造方法,此时A的成员变量都没有初始化,全部是默认的0,在B中调用draw时,根据运行时动态绑定,会执行A的draw()方法,所以打印的radius为0,执行完B的构造方法之后,才执行A的成员变量初始化,radius=1,然后再执行构造方法中的代码,此时A中的radius才被赋值为5。
?
把A(int radius)改成这样:public A(int radius) { System.out.println("radius = " + radius);this.radius = radius; System.out.println("A constructor"); }那么输出应该是B constructorA.draw(), radius = 0radius =1A constructor可是输出确是B constructorA.draw(), radius = 0radius =5A constructor
?改成这样的话,当执行System.out.println("radius = " + radius); 这句话的时候,这里的radius的值是指形参的值(此时的radius不是指的A中的radius,而是把离他最近的radius的值赋给他),如果你要看A中的radius的值的话,应该使用this.radius,这样的话它的值才是1。
?
A(int radius){System.out.println("radius = " + radius); this.radius = radius; System.out.println("A constructor");}
radius会使A中定义的radius在这个构造函数中失效(即被形参作用域覆盖)。要是把第一条输出语句中的radius改为this.radius就会输出1了。