日期:2014-05-20  浏览次数:20774 次

java 继承
package com.bag;

class Super
{
int i = 10;

Super()
{
print();
i = 20;
}

void print()
{
System.out.println(i);
}
}

public class Sub extends Super

int j=30; 
Sub()
{
print();
j=40; 


void print()

System.out.println( j); 



public static void main(String[] args)

System.out.println(new Sub().j); 



}



结果是 0
  30
  40

为什么不是 10 
  30
  40













------解决方案--------------------
因为子类的print()方法,覆盖了父类额print()方法.运行时候 new Sub.j(),首先去Sub类了找j的属性,Sub是继承的Super类,直接调用Super无参构造器,Super无参构造器了,调用了print()方法,执行print()方法,这个方法是被子类覆盖的,所以是调用的子类方法,输出j,j并没有赋值,int类型成员变量初始值为0所以输出0,之后执行子类Sub方法,Sub调用print(),输出j,子类里全局变量j值是30,所以输出30,之后继续执行j=40,找到Sub.j的值,输出40。

总结就是子类方法覆盖了父类方法,所以父类print()调用的是子类方法。int成员变量初始值为0,所以输出0。其他成员变量初始值是什么可以自己测试看看。
------解决方案--------------------
print()方法覆盖是没错。
也要了解到一个对象实例化的步骤,基本可以分为五个步骤。
在执行new Sub();这句话的时候,先调用父类的构造方法Super();父类构造方法中调用的print()方法是子类Sub中的方法,此时还没有调用子类中的构造方法给j显性初始化赋值,所以j在栈内存中存放的还是int型的默认值0,所以此时输出0;
接着调用子类Sub中的构造方法Sub();调用的同时为j显性初始化赋过值了,所以print();方法中j=30;
最后,在Sub的构造方法中为j改变赋值,所以此时new Sub().j=40.
------解决方案--------------------


过程如下:
1. 虚拟机试图访问Sub.main这个静态方法
2. 当一个类第一次被访问的时候,才会被加载,如果有静态变量或称为类变量,那么在此
加载时会被初始化
3. 加载Sub类的时候,虚拟机注意到它有一个基类Super,那么Super类也会被加载
4. 当new Sub()的时候,第一件事儿就是在内存中划出一块足够存储Sub对象的空间,
这块空间会被清零,也就是说Sub对象的所有实例变量都会得到一个默认值,对于
这里的i,j就是0,如果是引用类型就是null
5. 执行Sub构造器,Sub有父类,所以执行Sub构造器的第一步就是执行父类的构造器, 
构造器的执行过程是最让人迷惑的地方,下面试着做一下解释:

首先要明确构造器的作用,构造器的作用就是初始化对象,而不是创建对象。
其次要明确,执行构造器时第一要做的就是初始化对象,然后才是运行构造器中的语句。
什么叫初始化对象呢?就是按照语义从上到下依次执行一下你声明的字段。

哥们就说这么多,你要再不明白,没招儿啦!