类初始化及加载



                                                                       类初始化及加载

成员初始化

Java尽力保证:所有变量在使用前都能得到恰当的初始化。如果变量是类成员,Java装载时,能确保初始化成员变量,为没有赋值的成员赋初始值。

以下是基本类型的类成员及对应没有赋值时初始化的值。如果类里定义一个对象引用时,不将其初始化,此引用就会获得一个特殊值null

Data type   Initial value

Boolean   false

Char       

Byte      0

Short     0

Int      0

Long       0

Float      0

Double      0

引用类型    null

(注意:如果变量是局部变量,编译器不会初始化该变量,会造成编译出错。如果未初始化非基本类型的对象,就尝试使用它,就会出现运行时错误。)

</pre><pre class="java" name="code">public class Measurement{

static Person   man=new  Person();//定义成员man时,使其指向Person类的一个实

//Static Person   man;

public static void main(String[] args){

 

Measurement.man.speak();//如果定义man时,没有指定其实例,就使用Person类里的speak()方法,就会出错。

}

}


如果想指定初始化成员变量,可以在定义类成员变量的地方为其赋值。

二:构造器初始化

可用用构造器来对实例进行初始化。在运行时刻,可以调用方法或执行某些动作来确定初值,这为编程带来了更大的灵活性。但是要牢记:无法阻止自动初始化的进行,它将在构造器被调用之前发生。例如:

Public classCounter{

int i;

Counter(){i=7;}

}

I首先会被置0,然后变7

初始化顺序

在类的内部,变量定义的先后顺序决定了初始化的顺序,即使变量定义于散布在方法定义之间,他们仍然会在任何方法(包括构造器)被调用之前得到初始化。

//when the constructor is called to create 

//a window object,you’ll see a message:

Class Window{

      Window(int  marker){System.out.println(“Window(“+marker+”)”);}

}

class House{

      Window w1=new Window(1);//Before constructor

House(){

  //Show that we’re in the constructor

  System.out.println(“House()”);

  w3=new Window(33);//Reinitialize w3

}

Window w2=new Window(2);//After constructor

Void f(){System.out.println(“f()”);}

Window w3=new Window(3);

}

Public  class OrderOfInitialization{

      Public static void main(String[] args){

           House h=new House();

           h.f();//show that construction is done

      }

}

/*output:

Window(1)

Window(2)

Window(3)

House()

Window(33)

F()

*/

 静态数据初始化

无论创建多少个对象,静态成员都只占用一份存储区域。Static关键字不能应用于局部变量,因此它只能作用于域(作用于域和初始化成员变量一样。)。用static定义成员变量共享于各个实例,且初始化优先于非静态成员变量。

静态成员初始化顺序优先于非静态成员,静态成员初始化只执行一次。

//Specifying initial values in a class definition

class  Bowl{

      Bowl(int marker){

           System.out.println(“Bowl(“+marker+”)”);

      }

      void  f1(int marker){

           System.out.println(“f1(“+marker+”)”);

      }

}

class Table {

      static  Bowl bowl1=new Bowl(1);

      Table(){

           System.out.println(“Table()”);

           Bowl2.f1(1);

      }

      void  f2(int marker){

           System.out.println(“f2(“+marker+”)”);

      }

      static Bowl bowl2=new Bowl(2);

}

class Cupboard{

      Bowl bowl3=new Bowl(3);

      static  Bowl bowl4=new Bowl(4);

      Cupboard(){

                   System.out.println(“Cupboard()”);                                

                   Bowl4.f1(2);

      }

      void f3(int marker){

           System.out.println(“f3(“+marker+”)”);

      }

      static Bowl bowl5=new Bowl(5);

}

public class StaticInitialization{

      public static void main(String[] args){

           System.out.println(“Creating new Cupboard() in main”);

           new Cupboard();

           System.out.print(“Creating new Cupboard() in main”);

           new Cupboard();

           Table.f2(1);

           Cupboard.f3(1);

      }

      static Table table=new Table();

      static Cupboard cupboard=new Cupboard();

}

/*

//Output:

Bowl(1)

Bowl(2)

Table()

f1(1)

Bowl(4)

Bowl(5)

Bowl(3)

Cupboard()

f1(2)

Creating new Cupboard() in main

Bowl(3)

Cupboard()

f1(2)

Creating new Cupboard() in main

Bowl(3)

Cupboard()

f1(2)

f1(1)

f1(1)

*/

 

四:继承与初始化

在加载中,如果一个类有基类,编译器会注意到它有一个基类(这是由extends得知的),于是它继续进行加载。不管你是否打算产生一个该基类的对象,这都要发生。

如果该基类还有其自身的基类,那么第二个基类就会被加载,如此类推。接下来,根基类中的static初始化即会被执行,然后是下一个导出类,以此类推。

至此为止,必要的类都已经加载完毕,对象就可以被创建了。首先,对象中所有的基本类型都会被设为默认值,对象引用被设为null——这是通过将对象内存设为二进制零值而一举生成的。然后,基类的构造器会被调用。在基类构造器完成之后,实例变量按其次序被初始化。最后,构造器的其余部分会被执行。

例子:

class Glyph{

      void draw(){

           System.out.println(“Glyph.draw()”);

}

Glyph(){

  System.out.println(“Glyph() before draw()”);

  draw();

  System.out.println(“Glyph() after draw()”);

}

}

class RoundGlyph extends Glyph{

      private int radius=1;

      RoundGlyph(int r){

           radius=r;

           System.out.println(“RoundGlyph.RoundGlyph(),radius=”+radius);

      }

      void draw(){

           System.out.println(“RoundGlyph.draw(),radius=”+radius);

      }

}

public class PolyConstructors{

     public static void main(String[] args){

           new  RoundGlyph(5);

      }

}

/*Output

Glyph() before draw()

RoundGlyph.draw(),radius=0

Glyph() after draw()

RoundGlyph.RoundGlyph(),radius=5

*/

解析:1在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。

2如前所述那样调用基类构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph构造器之前调用),由于步骤1的缘故,我们此时会发现radius的值为0.

3按照声明的顺序调用成员的初始化方法。

4调用导出类的构造器主体。

 

五:总结

 如果一个类继承某个类,首先初始化根基类的静态成员(非静态成员暂不初始化,直到调用该类的构造器前初始化),然后是下一个导出类的静态成员,以此类推,直到最后一个类的静态成员被初始化。

到此为止,必要的类都已经加载完毕,对象可以创建了。首先,对象中的所有基本类型都会被设为默认值,对象引用被设为null。然后,基类构造器被调用,基类构造器调用之前,还未被初始化的实例变量按照类初始化,之后调用构造器。基类构造器和导出类的构造器都是一样,以相同的顺序来经历相同的历程。依次类推,直到调用到导出类的构造器。

 

友情提示:本文大部分参考 《Thinking in Java》,个人觉得这本书挺好的.!

 

 

 

你可能感兴趣的:(类加载,静态初始化,构造器初始化,成员初始化,继承和初始化)