类初始化及加载
一:成员初始化
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》,个人觉得这本书挺好的.!