62,614
社区成员
发帖
与我相关
我的任务
分享
public class A {
private String str = "A";
public A(){
aa();
}
public void aa(){
System.out.println("class A-aa:" + str);
}
}
public class B extends A{
private String str = "B";
public B(){
aa();
}
public void aa(){
System.out.println("class B-aa:" + str);
}
public static void main(String[] args) {
new B();
}
}
public learn.javavm.B();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: invokespecial #10; //Method learn/javavm/A."<init>":()V
4: aload_0
5: ldc #12; //String B
7: putfield #14; //Field str:Ljava/lang/String;
10: aload_0
11: invokevirtual #16; //Method aa:()V
14: return
LineNumberTable:
line 12: 0
line 9: 4
line 13: 10
line 14: 14
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Llearn/javavm/B;
执行顺序是:
1.先在堆中开辟B新对象的内存区域。
2. 1: invokespecial #10; //Method learn/javavm/A."<init>":()V
3. 5: ldc #12; //String B
7: putfield #14; //Field str:Ljava/lang/String;
4. 11: invokevirtual #16; //Method aa:()V
问题是为什么是null呢?其实前面几位答得已经很好了,我在这里补充一些。
首先在2步骤执行前,1步骤开辟了内存区域,但还未到3步骤去初始化str值。
其次为什么父类调用子类的aa()方法呢,其实这就是Java面向对象的关键特性——多态导致的。在对这种虚函数的加载之前,Java虚拟机的执行逻辑是这样的:
1.找到栈顶元素指向的实际对象类型,这里就是B。
2.从B中搜索,找到与方法的描述符和简单名称一致的方法,成功找到则返回执行方法。
3.从B的父类逆流向上逐个搜索,找到则返回执行该方法。
4始终没找到,则抛出AbstractMethodError
当父类和子类有Static时,先初始化Static,再初始化子类的Static,再初始化父类的其他成员变量->父类构造方法->子类其他成员变量->子类的构造方法。
A类构造函数执行aa()这个方法时,调用的是子类B中的aa()方法,但是此时str尚未初始化,所以str为默认值null。