public class aa
{
aa()
{ this("renqiang");
System.out.println("aa类的第一个构造方法");
}
aa(String s)
{
System.out.println("aa类的第二个构造方法");
}
}
class bb extends aa 
{
bb()
{ //super();
this("temp");

System.out.println("bb类的第一个构造方法");
}
bb(String b)
{
System.out.println("bb类的第二个构造方法");
}
public static void main(String args[])
{
bb t=new bb();
}
}/*********************************************************************
我的目的是按照以下的顺序输出如下:
aa类的第二个构造方法 aa类的第一个构造方法 bb类的第二个构造方法 bb类的第一个构造方法但是如果不注释super();的话,则会提示this必须放在constructor的第一句.
让人费解的是.如果注释super();的话,系统还是会默认的会把super()加上来调用
其父类的构造函数的.这样一来,this还不是放在第二句了吗?(即不是放在constructor
的第一句)但是系统此时却又不提示出错了,则正常的运行.如上面所输出的.
哪位能解释的清楚呢?*********************************************************************/

解决方案 »

  1.   

    class bb extends aa 
    {
    bb()
    { this("temp");
    System.out.println("bb类的第一个构造方法");
    }
    bb(String b)
    {super();
    System.out.println("bb类的第二个构造方法");
    }
    public static void main(String args[])
    {
    bb t=new bb();
    }
    }
      

  2.   

    编译的时候“提示this必须放在constructor的第一句”的目的在于,子类在构造过程中,如果要引用另一个构造方法,必须在“其它执行语句”的前面。而这里的“其它执行语句”,指的是子类里写的某些语句,不包括“父类里的语句”。事实上,父类的构造方法*一定*是要被首先调用的(无论是隐式的还是显式的)。这正是 Java 语法“严格”的表现,基本上可以说,你找不到它“不恰当”的地方  ;)
      

  3.   

    调用重载的构造函数只能调用一次,而且必须放到构造函数的第一句,由于你使用的是BB无参构造方法,所以SUPER是不必须写的,默认调用SUPER
      

  4.   

    我中楼主,首先谢谢MAQUAN的回答:
     maquan('ma:kju) ( ) 信誉:100    Blog   加为好友  2007-4-14 21:48:42  得分: 0  
     
     
       
    编译的时候“提示this必须放在constructor的第一句”的目的在于,子类在构造过程中,如果要引用另一个构造方法,必须在“其它执行语句”的前面。而这里的“其它执行语句”,指的是子类里写的某些语句,不包括“父类里的语句”。事实上,父类的构造方法*一定*是要被首先调用的(无论是隐式的还是显式的)。这正是 Java 语法“严格”的表现,基本上可以说,你找不到它“不恰当”的地方  ;)
    您所说的:"而这里的“其它执行语句”,指的是子类里写的某些语句,不包括“父类里的语句”。"虽然super();是父类的语句,但是如果说把我上面程序的//super()注释去掉,则不能编译,
    说this必须在第一行.
    还有你可能没有明白我的意思,如果把//super()加上注释的话,也就是说java也会首先执行super()再执行this这样程序会正常的编译运行.但是此时this不是相当于放在了第二句了吗?虽然super()是隐式执行的.  
     
      

  5.   

    道理很简单,除了java.lang.Object之外的任意一个类(像上面的aa,bb),
    只要aa或bb类的源码中定义了构造方法,且构造方法的第一条语句
    不是“this(可选参数)”或“super(可选参数)”调用,
    编译器都会默认产生一条super()语句,作为这个构造方法的第一条语句。这样做的目的就是保证初始化子类前,所有父类都已正确初始化。因为你是通过bb t=new bb()开始的,
    所以先调用bb()构造方法,因bb()构造方法第一条语句是this("temp");
    所以编译器不会为bb()构造方法产生super()语句,JVM接着不会调用
    aa类的构造方法,而是转到bb(String b),因bb(String b)内部第一条
    语句不是“this(可选参数)”或“super(可选参数)”调用,所以编译器
    已为它产生了一条super()语句,JVM接着调用aa(),再到aa(String s),
    再到java.lang.Object的Object()调用结束。
    所以结果就是:aa类的第二个构造方法
    aa类的第一个构造方法
    bb类的第二个构造方法
    bb类的第一个构造方法另外“this(可选参数)”或“super(可选参数)”语句只能出现在最前面,
    只能二选一,这是语言规范,没什么好解释的。
    有不明白的地方用javap -verbose bb看看字节码或者看看javac的源码
    在com.sun.tools.javac.comp.MemberEnter类有点说明
      

  6.   

    楼上的朋友,首先谢谢你这这么详细的给我讲解.
    但是您所说的:"因bb(String b)内部第一条
    语句不是“this(可选参数)”或“super(可选参数)”调用,所以编译器
    已为它产生了一条super()语句"如果这样的话,在产生了一条super()语句之后
    那么他后面的语句就不执行了吗?也就是说bb(String b)内还有这样一句话:"System.out.println("bb类的第二个构造方法");".如果不是的话,而且照你所说的流程的话.输出的第一句话应该是:"bb类的第二个构造方法"才对啊?
      

  7.   

    那么他后面的语句就不执行了吗?
    ===============================
    执行。相当于是
    bb(String b) {
       super();
       System.out.println("bb类的第二个构造方法");
    }用javap -verbose bb查看反编译后的代码也跟上面类似:
    bb(java.lang.String);
      Code:
       Stack=2, Locals=2, Args_size=2
       0:   aload_0
       1:   invokespecial   #6; //Method aa."<init>":()V  //这里就当相于super()
       4:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
       7:   ldc     #7; //String bb类的第二个构造方法
       9:   invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V //这里就当相于System.out.println("...")
       12:  return
      

  8.   

    输出的第一句话应该是:"bb类的第二个构造方法"才对啊?
    =================================================
    不对。调用super()就相当于调用
    aa() {
      this("renqiang");
      System.out.println("aa类的第一个构造方法");
    }
      

  9.   

    我所说的调用结束指的是super()到java.lang.Object的Object()构造方法,
    但是每个子类的构造方法中剩余的代码还是要继续执行的,你可以想象一下递归调用的流程。好了,就聊这么多,太多细节还得说编译流程,各类JVM指令。
      

  10.   

    我认为这个问题是这样的:this()用来指明调用本类的重载构造方法, 在那里也是会有super的,所以就没必要在本方法中写了呵呵,对不对?