1.普通变量的初始化
看如下程序
- class Window{
- public Window(int maker) {
- System.out.println("Window("+maker+")");
- }
- }
- class House{
- Window w1 = new Window(1);
- public House() {
- System.out.println("House()");
- w3 = new Window(33);
- }
- Window w2 = new Window(2);
- void f(){
- System.out.println("f()");
- }
- Window w3 = new Window(3);
- }
- public class Test {
- public static void main(String[] args) {
- House h = new House();
- h.f();
- }
- }
- /*
- 结果如下:
- Window(1)
- Window(2)
- Window(3)
- House()
- Window(33)
- f()
- */
分析:普通变量在类中的任何方法(包括构造函数)之前初始化(规则一)。
2.静态变量的初始化
- class Bowl{
- public Bowl(int maker) {
- System.out.println("Bowl("+maker+")");
- }
- void f1(int maker){
- System.out.println("f1("+maker+")");
- }
- }
- class Table{
- static Bowl bowl1 = new Bowl(1);
- static Bowl bowl2 = new Bowl(2);
- public Table() {
- System.out.println("Table()");
- bowl2.f1(1);
- }
- void f2(int maker){
- System.out.println("f2("+maker+")");
- }
- }
- class Cupboard{
- Bowl bowl3 = new Bowl(3);
- static Bowl bowl4 = new Bowl(4);
- static Bowl bowl5 = new Bowl(5);
- public Cupboard() {
- System.out.println("cupboard()");
- bowl4.f1(2);
- }
- void f3(int maker){
- System.out.println("f3("+maker+")");
- }
- }
- public class Test {
- static Table table = new Table();
- static Cupboard cupboard = new Cupboard();
- public static void main(String[] args) {
- System.out.println("creating new cupboard() in main");
- new Cupboard();
- System.out.println("creating new cupboard() in main");
- new Cupboard();
- table.f2(1);
- cupboard.f3(1);
- }
- }
- /*
- 结果如下:
- 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)
- f2(1)
- f3(1)
- */<span style="color:#ff0000">
- </span>
分析:
1.首先程序总共有4个类(Bowl,Table,Cupboard,Test),Bowl没有静态变量和静态方法;Table中有静态变量bowl1、bowl2;Cupboard中有普通变量bowl3,静态变量bowl4、bowl5;Test中有静态变量table、cupboard。
2.根据规则:使用static命名的变量或者使用static{}包括起来的区域,都在类被加载时进行初始化(规则二)。
3.虚拟机首先加载Test,需要初始化table变量,加载Table类。Table类中有静态变量bowl1,bowl2,初始化它们,输出"Bowl(1),Bowl(2)",再调用构造函数来new对象,输出"Table(),f1(1)"。然后加载Cupboard类,初始化静态变量bowl4,bowl5,输出"Bowl(4),Bowl(5)",调用构造函数来new对象,首先初始化普通变量bowl3,输出"Bowl(3)",然后构造函数,输出"cupboard(),f1(2)"。
4.执行main方法,先输出"creating new cupboard() in main",执行new Cupboard(),这时静态变量都初始化了,不必继续初始化。初始化一般变量bowl3,输出"bowl3",然后调用构造函数,输出"cupboard(),f1(2)"。在输出"creating new cupboard() in main",同理输出"bowl3,cupboard(),f1(2)",最后继续执行main函数,输出"f2(1),f3(1)"。
3.静态代码块的初始化
- class Spoon{
- public Spoon(int maker) {
- System.out.println("Spoon("+maker+")");
- }
- static int i;
- static Spoon s = new Spoon(1);
- static{
- System.out.println("static code ");
- i = 47;
- }
- }
- public class Test {
- public static void main(String[] args) {
- new Spoon(2);
- }
- }
- /*
- Spoon(1)
- static code
- Spoon(2)
- */
- /*
- 如果写成
- static{
- System.out.println("static code ");
- i = 47;
- }
- static Spoon s = new Spoon(1);
- 结果为:
- static code
- Spoon(1)
- Spoon(2)
- */
分析:静态代码块跟静态变量都是类加载时进行初始化的(同等条件下,初始化顺序由书写顺序决定)
4.非静态代码块
- class Spoon{
- public Spoon(int maker) {
- System.out.println("Spoon("+maker+")");
- }
- static int i;
- static Spoon s = new Spoon(1);
- static{
- System.out.println("static code ");
- i = 47;
- }
- int a;
- //非静态代码块与直接为变量赋值效果相同,只不过可以写更为复杂的代码,非静态代码块一般用于内部类中
- {
- System.out.println("non-static instatnce");
- a = 1;
- }
- }
- public class Test {
- public static void main(String[] args) {
- new Spoon(2);
- new Spoon(3);
- }
- }
- /*
- non-static instatnce
- Spoon(1)
- static code
- non-static instatnce
- Spoon(2)
- non-static instatnce
- Spoon(3)
- */
分析:
1.main函数执行new Spoon(2)语句,首先加载Spoon类,先初始化静态变量s,s调用new Spoon(1),此时类Spoon已经加载,所以不用管静态变量和静态代码块了,然后调用非静态代码块和构造函数,输出"non-static code,spoon(1)"。
2.初始化静态代码块,输出"static code"。
3.执行new spoon(2)语句输出“non-static instatnce,Spoon(2)“。
4.执行"new spoon(3)"语句输出”non-static instatnce,Spoon(3)”。
可以尝试调换静态变量s和静态代码块的顺序,发现只是1和2的先后顺序改变而已。
在看下面这个程序
- <span style="font-size:18px">class T{
- public T() {
- System.out.println("T constructor");
- }
- }
- class Spoon{
- public Spoon(int maker) {
- System.out.println("Spoon("+maker+")");
- }
- int a;
- //非静态代码块与直接为变量赋值效果相同,只不过可以写更为复杂的代码,非静态代码块一般用于内部类中
- {
- System.out.println("non-static instatnce");
- a = 1;
- }
- T t1 = new T();
- }
- public class Test {
- public static void main(String[] args) {
- new Spoon(2);
- }
- }
- /*
- non-static instatnce
- T constructor
- Spoon(2)
- */
- </span>
通过这个程序,可以发现非静态变量和非静态代码块顺序由书写顺序决定。
5.总结:
以Dog类为例
1.当第一次执行到需要使用Dog类时(如Dog d = new Dog),java首先通过寻找classpath来找到Dog.class,进行加载.
2.初始化Dog类的静态变量和静态代码块(按书写顺序,若静态变量或代码块中还有new Dog,此时不用再管静态变 量和代码块了,如第五个程序中的"static Spoon s = new Spoon(1)")。
3.系统给类分配足够大的内存空间,初始化非静态变量和非静态代码块(顺序由书写顺序决定)
4.最后执行Dog类的构造函数。
5.以后如果还要new Dog类对象时(不是第一次使用了),重复3和4的步骤,不会再去初始化静态变量和静态代码 块了。
大家可以自己写程序实验一下。