构造函数

"每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。"

这句话怎么理解

所有代码都经过测试,测试环境:

java   version   "1.4.0-rc "

Java(TM)   2   Runtime   Environment,   Standard   Edition   (build   1.4.0-rc-b91)

Java   HotSpot(TM)   Client   VM   (build   1.4.0-rc-b91,   mixed   mode)


缺省构造函数的问题:base类是父类,derived类是子类,首先要

说明的是由于先有父类后有子类,所以生成子类之前要首先有父类。

class是由class的构造函数constructor产生的,每一个class都有

构造函数,如果你在编写自己的class时没有编写任何构造函数,那么

编译器为你自动产生一个缺省default构造函数。这个default构造函数

实质是空的,其中不包含任何代码。但是一牵扯到继承,它的问题就出现

了。

如果父类base   class只有缺省构造函数,也就是编译器自动为你产生的。

而子类中也只有缺省构造函数,那么不会产生任何问题,因为当你试图产生

一个子类的实例时,首先要执行子类的构造函数,但是由于子类继承父类,

所以子类的缺省构造函数自动调用父类的缺省构造函数。先产生父类的实例,

然后再产生子类的实例。如下:

class   base{

}

class   derived   extends   base{

public   static   void   main(String[]   args){

derived   d=new   derived();

}

}

下面显式地加上了缺省构造函数:

class   base{

base(){

System.out.println( "base   constructor ");

}

}

class   derived   extends   base{

derived(){

System.out.println( "derived   constructor ");

}

public   static   void   main(String[]   args){

derived   d=new   derived();

}

}

执行结果如下:说明了先产生base   class然后是derived   class

base   constructor

derived   constructor

我要说明的问题出在如果base   class有多个constructor

derived   class也有多个constructor,这时子类中的构造函数缺省

调用那个父类的构造函数呢?答案是调用父类的缺省构造函数。

但是不是编译器自动为你生成的那个缺省构造函数而是你自己显式地

写出来的缺省构造函数。

class   base{

base(){

System.out.println( "base   constructor ");

}

base(int   i){

System.out.println( "base   constructor   int   i ");

}

}

class   derived   extends   base{

derived(){

System.out.println( "derived   constructor ");

}

derived(int   i){

System.out.println( "derived   constructor   int   i ");

}

public   static   void   main(String[]   args){

derived   d=new   derived();

derived   t=new   derived(9);

}

}

D:"java"thinking"think6> java   derived

base   constructor

derived   constructor

base   constructor

derived   constructor   int   i

如果将base  类的构造函数注释掉,则出错。

class   base{

//   base(){

//   System.out.println( "base   constructor ");

//   }

base(int   i){

System.out.println( "base   constructor   int   i ");

}

}

class   derived   extends   base{

derived(){

System.out.println( "derived   constructor ");

}

derived(int   i){

System.out.println( "derived   constructor   int   i ");

}

public   static   void   main(String[]   args){

derived   d=new   derived();

derived   t=new   derived(9);

}

}

 

D:"java"thinking"think6> javac   derived.java

derived.java:10:   cannot   resolve   symbol

symbol   :   constructor   base   ()

location:   class   base

derived(){

^

derived.java:13:   cannot   resolve   symbol

symbol   :   constructor   base   ()

location:   class   base

derived(int   i){

2   errors

说明子类中的构造函数找不到显式写出的父类中的缺省

构造函数,所以出错。

那么如果你不想子类的构造函数调用你显式写出的父类中的缺省

构造函数怎么办呢?

如下例:

class   base{

//   base(){

//   System.out.println( "base   constructor ");

//   }

base(int   i){

System.out.println( "base   constructor   int   i ");

}

}

class   derived   extends   base{

derived(){

super(8);

System.out.println( "derived   constructor ");

}

derived(int   i){

super(i);

System.out.println( "derived   constructor   int   i ");

}

public   static   void   main(String[]   args){

derived   d=new   derived();

derived   t=new   derived(9);

}

}

 

D:"java"thinking"think6> java   derived

base   constructor   int   i

derived   constructor

base   constructor   int   i

derived   constructor   int   i

super(i)表示父类的构造函数base(i)请大家注意

一个是super(i)一个是super(8)

大家想想是为什么??

结论:子类如果有多个构造函数的时候,父类要么没有构造函数,

让编译器自动产生,那么在执行子类构造函数之前先执行编

译器自动产生的父类的缺省构造函数;要么至少要有一个显

式的缺省构造函数可以让子类的构造函数调用。


java构造函数的调用顺序:

当一个复杂的对象被构造时,它的构造函数按下面的顺序被调用(that the order of constructor calls for a complex object is as follows)

   1.其基类(base-class)的构造函数被调用,这个步骤以递归的方式重复,所以最底层(the root ofhierarchy)的构造函数首先被执行,然后是它上一层派生类(the next-derived class)...直到最顶层的派生类(themost-derived class).

The base-class constructor is called. Thisstep is repeated recursively such that the root of the hierarchy isconstructed first, followed by the next-derived class, etc., until themost-derived class is reached.)

    2.如果有包含关系(composition),那么它的成员对象按照声明的顺序被构造.

Member initializers are called in the order of declaration.

    3.派生类构造函数的内容(body)被执行.

The body of the derived-class constructor is called.

    一个实例:


class Cake{
   Cake(){System.out.println("Cake()");}
}

class Meal {
  Meal() { System.out.println("Meal()"); }
}

class Bread {
  Bread() { System.out.println("Bread()"); }
}

class Cheese {
  Cheese() { System.out.println("Cheese()"); }
}

class Lettuce {
  Lettuce() { System.out.println("Lettuce()"); }
}

class Lunch  extends Meal {
  Lunch() { System.out.println("Lunch()"); }
}

class PortableLunch  extends Lunch {
    // if make derived-class object as the menber of the base-class will lead a infinite
   
// loop and program will stop because of the memory consumed
   
   
// private Sandwich s=new Sandwich(); 
   private Cake a= new Cake();
  PortableLunch() { System.out.println("PortableLunch()");}
}

public  class Sandwich  extends PortableLunch
{
   private Bread b =  new Bread();
   private Cheese c =  new Cheese();
   private Lettuce l =  new Lettuce();
  
   public Sandwich() {
    System.out.println("Sandwich()");
  }
  
   public  static  void main(String[] args)  {
     new Sandwich();
  }
}

输出:

Meal()
Lunch()
Cake()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()

  main()函数中要构造一个Sandwich的对象,调用(并不是执行)它基类PortableLunch的构造函数,PortableLunch又递归的调用,然后是Meal,Meal是继承的最底层的基类(不算Object)所以它的构造函数首先被执行,然后按次序返回到Lunch,PortableLunch,但在PortableLunch的构造函数被执行之前,它的成员对象Cakea先按照声明的顺序被构造.然后执行PortableLunch(),接着是Sandwich的成员对象,最后是Sandwich().

注:被注释掉的代码,将base-class的对象作为derive-class的成员对象,这样会递归无法结束,最后程序因堆栈耗尽而结束(Exception in  thread main java.lang.StackOverflowError).


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值