声明这样一个类public class EMyException extends Exception {
   public EMyException(String s) {
     String msg = MessageFormat.format("{0}", s);
     super(msg);
   }
}这样会导致一个编译错误,信息原文我记不住,大概意思就是构造器中的构造器调用必须在第一个语句。好了,改成public class EMyException extends Exception {
   public EMyException(String s) {
     super(MessageFormat.format("{0}", s));
   }
}编译就通过了。
两种形式相比较,第一种形式不过是多了一个String msg的声明,为什么就导致编译错误呢?第二种形式为什么就可以通过编译呢?第二形式比第一种形式对于VM来说又有什么保障呢?迷惑!

解决方案 »

  1.   

    构造器主要用来分配内存等JVM初始化,所以必须第一个调用,否则你的String还没有内存空间呢,哪里来的引用!
      

  2.   

    对象初始化会首先显式或隐式调用父类的构造函数,因此super必须放在构造函数第一行
      

  3.   

    class Base() {}
    class Child() extends Base {}
    在Child的构造函数中第一个要调用Base的构造函数,这个的原因是这样的:
    1。从反证的角度来说,
    如果你第一句不是super,而是调用父类的某个方法,那么父类和其成员还没有构造呢,你调用什么呢?
    2。从理论的角度来说,
    根据Liskov的可替代原则,子类首先也是个父类,is-a的关系不满足,继承就有问题了。所以一定是父类的构造函数先被调用完毕的。
    3。从C++的角度来说,也是如此:
    Child() : Base() {}
    有这样的语法,可以看到汇编,在构造子类的成员和虚表之前,父类要被构造完毕。
      

  4.   

    上面我着重强调了调用完毕,是因为确实是先调用了子类的构造函数,但是子类CTOR会SUPER,父类的构造函数要先于子类的构造函数调用完毕。还有,上面的代码有语法错误,因为我很久不写Java代码了。
      

  5.   

    谢谢,以前不是弄java的,所以比较迷惑。那么,按照你的说法,难道第二种形式
    super(MessageFormat.format("{0}",   s)); 
    中的
    MessageFormat.format("{0}",   s)
    就不需要分配一个string类型的内存变量?>构造器主要用来分配内存等JVM初始化
    我觉得
    分配内存和初始化是两个过程,new操作符是用来分配内存的,而构造函数是用来初始化的。>否则你的String还没有内存空间呢,哪里来的引用!
    这我就更闹不明白了, String msg是一个临时变量,和被构造的对象的内存空间是没有关系的,就像在一个静态方法里面声明一个临时变量,根本不需要对象指针我是这样觉得,比方说:
    EMyException = new EMyException(s);
    这样的调用,形象地说,new操作符首先导致EMyException实例的内存分配,然后才调用初始化函数,也就是构造函数EMyException(),
    new => EMyExceptionIntancePtr = getMem(InstanceSizeOf(EMyExcption));
    EMyException(s) => EMyException.Constructor(EMyExceptionInstancePtr, s);
      

  6.   

    楼上,你的理解是正确的,
    new是用来分配内存的,在你new Object的时候,就已经把父类成员需要的内存分配好了,特别是原始变量。父类构造函数是用来初始化这些成员的,以及一些隐藏在内部的数据结构。
    比如类似的函数表。要不JVM指令 invokevirtual的时候,上哪里找具体哪个对象的哪个方法啊?
      

  7.   

    ok,既然如此,为什么在super()以前不让调用String   msg   =   MessageFormat.format("{0}",   s); 我这条语句又没有引用对象的任何成员,这有点说不过去吧
      

  8.   

    这个是语法。理论上你在super之前做些操作,完全不触及父类,也是可以的,但是语法不让。比如前面写个int a = 1,着谁惹谁了? 但是语法不让
      

  9.   

    我刚才测了一下,发现,如果
    super(expr);
    中expr涉及成员或者this,会出现编译错误那么既然如此,其实应该允许super()之前调用不涉及成员的语句才对
      

  10.   


    ------赞成。
    特别是 this(),我觉得更有可能说他不合理,如果构造器里调用的是this(1);
    而这个this(1);的声名为
     this( int i){
        int i=1;
         //随便做点跟  父类  无关的事,怎么了吗,}
    这个this(1);
    就不一定非要在第一行的吧。