----------个人见解,如有不对之处,还请各路高人、老鸟给予指正:
知识基础: 变量和方法在jvm中的存储:
a).静态变量:存储在jvm的栈中,整个jvm只此一份。
b).成员变量: 存储在jvm的堆中,每个实例都有一份。
c). 方法:存储在jvm的栈中,整个jvm中也是只此一份。
先提出几个问题(java继承方面的):
1.在一个父类被多个子类继承时,这些子类所访问的父类成员变量是同一个吗?
2.在问题 1 的基础上,如果父类是个抽象类呢,会是怎样?
3.在问题1和2的基础上,如果子类通过父类的某个方法,访问父类的某个私有的成员变量,会是怎样?
4.在一个父类被多个子类继承时,子类继承到的父类成员变量在jvm中的存储是怎样的?
第一个问题:
测试环境:
类Z:
public class Z {
int i=2;
}
类A:
public class A {
Z z = new Z();
public void printI(){
System.out.println("A:"+ z.hashCode());
}
}
类B:
public class B extends A{
public B(){
}
public void printIi(){
System.out.println("B:"+ z.hashCode());
}
}
类C:
public class C extends A{
public void printIi(){
System.out.println("C:"+ z.hashCode());
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
A a = new A();
B b =new B();
C c=new C();
a.printI();
b.printI();
c.printI();
a.printI();
b.printIi();
c.printIi();
}
}
运行结果:
A:903470137
A:1913208269
A:1018730552
A:903470137
B:1913208269
C:1018730552
答案显而易见,所返回的并不是同一个变量。也就是说,在初始化子类时,父类会首先得到初始化。其实这里的“父类会首先得到初始化”有更深的理解:在初始化父类的时候,会把父类所有的成员变量进行初始化(static变量除外,因为早在类加载的时候静态变量已被初始化了),在jvm中会为父类划出一块内存区域来存放这些变量,并将这些变量的引用给了当前初始化的子类,而此时父类的方法块,还是原来的同一个方法块。因此,当一个父类被多个子类继承时,该父类的成员变量就会被初始化多个副本,且这些副本的引用分配给了相应的子类。
第二个问题:测试环境:
B,C,Z类代码不变。
A类:
public abstract class A {
Z z = new Z();
public void printI(){
System.out.println("A:"+ z.hashCode());
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
// A a = new A();
B b =new B();
C c=new C();
// a.printI();
b.printI();
c.printI();
// a.printI();
b.printIi();
c.printIi();
}
}
运行结果:
A:903470137
A:1913208269
B:903470137
C:1913208269
答案:不是同一个变量,原理同第一个问题。
第3个问题:
测试环境:
Z类不变。
A类:
public abstract class A {
private Z z = new Z();
public void printI(){
System.out.println("A:"+ z.hashCode());
}
}
B类:
public class B extends A{
}
C类:
public class C extends A{
}
public class Test {
public static void main(String[] args) {
B b =new B();
C c=new C();
b.printI();
c.printI();
}
}
在测试类中b,c调用的都是父类中的printI();
运行结果:
A:903470137
A:1913208269
答案:不是同一个变量。尽管此时父类中的成员变量z是私有的,子类无法直接调用。但是从结果上来看,通过测试程序的这种条用方法,所调用的z对象仍然不是同一个对象。也就说明了:在初始化父类的时候,父类的私有变量也会被初始化,只不过子类无法直接调用而已。
第4个问题:
在jvm中会为父类划出一块内存区域来存放这些变量,并将这些变量的引用给了当前初始化的子类,而此时父类的方法块,还是原来的同一个方法块。因此,当一个父类被多个子类继承时,该父类的成员变量就会被初始化多个副本,且这些副本的引用分配给了相应的子类。
以上内容如有不对的地方,还请指出,以便改正,多谢!
原创:转载请说明出处。