tij中的习题:
class BaseWithPrint {
  public BaseWithPrint() {
  p.println("BaseWithPrint()");
  print();
  }
  public void print() {
    System.out.println("BaseWithPrint.print");
  }
} class DerivedWithPrint extends BaseWithPrint {
  int i = 47;
  public DerivedWithPrint() {
  p.println("DerivedWithPrint()");
  }
  public void print() {
    System.out.println("i = " + i);
  }
}public class GetFile {

public static void main( String args[] ){
DerivedWithPrint dp = new DerivedWithPrint();
    dp.print();
}
}
输出结果如下:
在父类构造函数BaseWithPrint()中调用print(),既然是在父类的构造函数里,那么子类自然还没有构造,其成员函数按说也应该是不存在的呀!可是为什么这时可以调用子类的print()呢?
小弟初学java,问得可能比较幼稚,哪位前辈指点一下吧!

解决方案 »

  1.   

    你生成的(new)是了类对象。当然会有子类的成员变量。父类的print()方法会被子类的方法覆盖。只是用父类的句柄来引用子类对象,就像Object obj = new String("dd");
      

  2.   

    可能说得不是很清楚,输出结果:BaseWithPrint()
    i = 0
    DerivedWithPrint()
    i = 47"i=47"没什么说的,我奇怪的是"i=0",此时DerivedWithPrint还没有被构造,Print()又不是Static型的,为什么就可以调用了呢?就好比一个对象还没有构造,如何能调用其成员呢?
      

  3.   

    多肽的机制会自动查找这个方法是否被子类重写了,如果是的话就直接调用这个方法,和父类是否被初始化没关系的吧,因为这个方法在class里是存在的。类里的primitive变量是会被自动初始化的。
      

  4.   

    primitive不是指变量或对象吗?
    方法也可以是primitive的?
      

  5.   

    to crazycy(崔毅):
    类加载时不是首先初始化static的成员吗?
    如果加载后成员函数就存在了(而与是否有这个类的实例无关),那么static的方法和non-static的方法有什么区别呢?
      

  6.   

    DerivedWithPrint dp = new DerivedWithPrint();  
    //JVM检查到DerivedWithPrint有父类BaseWithPrint,于是将其一齐载入
    //现在开始初始化,首先为成员变量分配空间,如果是基本数据类型将其初始化,因此这里i被初始化为0
    //现在开始执行构造函数,首先执行父类构造函数 BaseWithPrint(),打印BaseWithPrint()
      然后是print(),由于这时候new的对象是DerivedWithPrint,因此调用DerivedWithPrint   overwrite的print方法 ,打印i = 0
    //接下来是DerivedWithPrint类自己的构造函数,成员变量赋初值 ,i被赋为47,然后是DerivedWithPrint(){}中的方法,打印DerivedWithPrint() i = 47
      

  7.   

    对了,i=47是 dp.print();打印出来的
      

  8.   

    一、运行时刻
      a +----+  -+---+-
        |    |        
        |    |   A
        |    |   
      b +----+  -+-  C
        |    |    
        |    |   B
        |    |
      c +----+  -+---+-我先用这个图表示类及其子类在内存中的逻辑概念上的分布。
    其中:
    1) 图形中的方框表示类在内存中的存储范围。
    2) A表示从a点到b点的内存区
    3) B表示从b点到c点的内存区
    4) C表示从a点到c点的内存区现在有一个类SuperClass及其子类SubClass被加载到内存。其中SuperClass加载于内存区A,那么SubClass占用哪一部分内存呢?正确答案是C而不是B。二,从代码角度观察
    对于继承,我们首先应该这样理解,代码中使用继承,只是为了减少代码量(那位,先把砖头放下),而不管父类还是子类,都是相对独立的类。当一个子类继承自其父类时,从代码角度,就是把其父类的代码重写一遍,然后再加上额外的代码,从而,成其子类。其实,这一工作是编译器完成的,当然也不是重写代码,但是我们可以这么直观的理解。我按照这种思路改造你的DerivedWithPrint,得到下面的代码:// 注意,去掉了extends
    class DerivedWithPrint {
      int i = 47;
      public DerivedWithPrint() {    //来自BaseWithPrint
        p.println("BaseWithPrint()");
        print();    // 本地
        p.println("DerivedWithPrint()");
      }  public void print() {    
        System.out.println("i = " + i);
      }
    }这就是DerivedWithPrint类在运行时刻应该执行的命令及顺序。因为原来的DerivedWithPrint中也有print方法,所以覆盖了其父类的print方法。上述过程好像叫做类的扁平化。注意,如果原DerivedWithPrint的print方法中有super.print()字样,那么扁平化之后的print方法应该这样:  public void print() {
        System.out.println("BaseWithPrint.print");
        System.out.println("i = " + i);
      }三,应该清楚了吧?
      

  9.   

    谢谢楼上UnAgain()老兄,关于子类、父类这块的调于明白了。还有一点疑问,我知道在C里面一个函数对应了一段可执行的代码,这些代码是存在内存中某段区域的,Java中是不是也是如此呢?如果是的话,那么类的成员函数(non-static)对应的那些内存区域到底是一个类共同拥有一段呢?还是每个对象各自拥有一段?
      

  10.   

    实例方法和类方法都是共享的,区别就是实例有this指针
      

  11.   

    楼主不要用C的思维去套java,java里头没有一个用户栈的概念,所有的对象都分配在堆空间,java没有C/C++里头的delete销毁机制,它的垃圾收集是用垃圾收集器做的
      

  12.   

    类的成员方法,不管是不是static,在内存中只有一份拷贝。创建类的实例,即对象的时候,系统只会为其非静态的成员变量分配空间。
      

  13.   

    to UnAgain()
    既然成员方法在内存中只有一份拷贝,那静态的方法和非静态的方法有什么区别呢?仅仅是在形式上静态方法可以由类调用而非静态方法不可以吗?
      

  14.   

    this指针,其实每个非静态方法(也就是实例方法)都有个隐藏参数this, 通过此参数来区分到底调用的是哪个具体对象的方法....,而静态方法(也就是类方法)是没有此指针的