进行试验
1 class InitializeBlockClass{ 2 { 3 field =200; 4 } 5 public int field =100; 6 public InitializeBlockClass(int valve){ 7 this.field=valve; 8 } 9 public InitializeBlockClass(){ 10 11 } 12 } 13 public class Test { 14 15 public static void main(String[] args) { 16 InitializeBlockClass obj =new InitializeBlockClass(); 17 System.out.println(obj.field); 18 19 obj =new InitializeBlockClass(300); 20 System.out.println(obj.field); 21 22 } 23 24 }
请依据代码的输出结果,自行总结Java字段初始化的规律。
初始化顺序:
1.执行类成员定义时指定的默认值或类的初始化块,到底执行哪一个要看哪一个“排在前面”。
2.执行类的构造函数:类的初始化块不接收任何的参数,而且只要一创建类的对象,它们就会被执行。因此,适合于封装那些“对象创建时必须执行的代码”。
初始化模板:
Java进行初始化的地方有两个:初始化块和构造函数,其中初始化块又分为静态初始化块和实例初始化块。静态初始化块是类中由static修饰的初始化块,实例初始化块为类中没有任何关键字修饰的初始化语句。
如果在主函数中创建对象时没有形参时,如果在类中定义了公共的变量并给与了赋值,那么就会把值赋给主函数中的变量,再调用类中的默认构造函数,如果在主函数中创建对象时有形参,则调用类中对应的构造函数。
动手动脑
当多个类之间有继承关系时,创建子类对象会导致父类初始化块的执行。请自行编写示例代码验证结论
1 class Student//父类 2 { 3 String name; 4 { name="LI"; } 5 } 6 //子类继承父类 7 class Teacher extends Student{ 8 int age=20; 9 float wage =10000; 10 void show() 11 { 12 System.out.println("姓名:"+name); 13 System.out.println("年龄:"+age); 14 System.out.println("工资:"+wage); 15 } 16 } 17 public class Inherit { 18 public static void main(String[] args){ 19 20 Teacher teacher = new Teacher(); 21 teacher.show(); 22 } 23 }
动手动脑2
请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。
1 class Root 2 { 3 static{ 4 System.out.println("Root的静态初始化块"); 5 } 6 { 7 System.out.println("Root的普通初始化块"); 8 } 9 public Root() 10 { 11 System.out.println("Root的无参数的构造器"); 12 } 13 } 14 class Mid extends Root 15 { 16 static{ 17 System.out.println("Mid的静态初始化块"); 18 } 19 { 20 System.out.println("Mid的普通初始化块"); 21 } 22 public Mid() 23 { 24 System.out.println("Mid的无参数的构造器"); 25 } 26 public Mid(String msg) 27 { 28 //通过this调用同一类中重载的构造器 29 this(); 30 System.out.println("Mid的带参数构造器,其参数值:" + msg); 31 } 32 } 33 class Leaf extends Mid 34 { 35 static{ 36 System.out.println("Leaf的静态初始化块"); 37 } 38 { 39 System.out.println("Leaf的普通初始化块"); 40 } 41 public Leaf() 42 { 43 //通过super调用父类中有一个字符串参数的构造器 44 super("Java初始化顺序演示"); 45 System.out.println("执行Leaf的构造器"); 46 } 47 48 } 49 50 public class TestStaticInitializeBlock 51 { 52 public static void main(String[] args) 53 { 54 new Leaf(); 55 56 57 } 58 }
如果定义初始化块时使用了static修饰符,则变成了静态初始化块。静态初始化块时类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行。
因此静态初始化块总是比普通初始化块先执行。
与普通初始化块类似的是,系统在类初始化阶段执行静态初始化块时,不仅会执行本类的静态初始化块,而且还会一直上溯到 java.lang.Object类,先执行java.lang.Object类中的静态初始化块,然后执行其父类的静态初始化块,最后才执行该类的静态 初始化块。经过这个过程,才完成了该类的初始化过程。只有当类初始化完成后,才可以在系统中使用这个类,包括访问类method、类Field,或者用这个类来创建实例。
一个有趣的问题
静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?
请编写代码验证你的想法。
1 class Exercise{ 2 3 int a=0; 4 static int b; 5 static public int getb(int newb) 6 { 7 b=newb; 8 System.out.println(b); 9 return b; 10 } 11 12 public int num() 13 { 14 int a=1; 15 return a; 16 } 17 } 18 19 public class Test2 { 20 21 public static void main(String[] args){ 22 23 Exercise e=new Exercise(); 24 25 e.getb(1111); 26 27 e.num(); 28 } 29 30 }
????????????
课后作业
使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数。请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”
1 public class Count { 2 public static int number; 3 public Count() 4 { 5 number ++; //统计个数,每创建一个类, number++ 6 } 7 8 public static int getValue() 9 { 10 return number; //返回得到number的最终的值 11 } 12 13 public static void main (String args[]) 14 { 15 Count c1 = new Count(); 16 Count c2 = new Count(); 17 Count c3 = new Count(); 18 Count c4 = new Count(); 19 System.out.println("创建对象的个数是:"+Count.getValue()); 20 } 21 }