聚沙成塔 积水成渊

你向神求助 说明你相信神的能力 可神没有帮你 说明神相信你的能力

类的初始化

        关于类的初始化问题 有些地方确实不好理解 分两次整理了一下 算是理顺一下思路

         一个类的整个生命周期是从被虚拟机加载到内存开始 到卸载出内存为止 这中间经过了七个步骤 他们分别是 加载 验证 准备 解析 初始化 使用 卸载
        我们最关心的应该要数类的初始化了 那么怎么样才会促使JVM对一个类进行初始化呢 有以下几个情况
        1.读取或设置一个类的静态字段(已在编译期把结果放入常量池的除外 有的地方说被final修饰的除外 下面会看到这个)的时候 以及调用一个类的静态方法的时候 
        2.new一个对象的时候(Thinking in Java 里有这样一个说法 构造方法也是static修饰的一个特殊方法 就是说当new一个对象的时候 其实是对这个类的静态方法的调用 根据上一条 它也会被初始化)
        3.虚拟机启动时 包含main()方法的那个类会首先被初始化.(main方法也是static修饰的)
        4.初始化一个类的时候 如果发现父类还没有初始化 会先初始化他的父类
        5.使用反射调用的时候 如果类还没有被初始化 则要先初始化
        以上这些也被称为是对类的主动使用 除此之外都不能引发初始化
        明白了这些 下面这段代码的输出结果就很容易想到了
        

package TestInit;

public class Init {
	static {
		System.out.println("Init !");
	}

	public static void main(String[] args) {
		new Sub();
	}
}

class Parent {
	static {
		System.out.println("Parent !");
	}
}

class Sub extends Parent {
	static {
		System.out.println("Sub !");
	}
}

/*
output:
Init !
Parent !
Sub !
*/


        再看一段代码
        
package TestInit;


public class Init {


	public static void main(String[] args) {
		System.out.println(Sub.a);
		Sub.fun();
	}
}


class Parent {
	public static int a = 3;
	static {
		System.out.println("Parent");
	}
	
	public static void fun(){
		System.out.println("fun");
	}
}


class Sub extends Parent {
	static {
		System.out.println("Sub");
	}
}

/*
output:
Parent
3
fun
*/
        输出结果有些出乎意料 Sub类始终都没被初始化 这是由于 对于静态字段和静态方法 只有直接定义这个静态字段或方法的类才会被初始化
        如果说这个还可以理解的话 那下面这段就更奇怪了

package TestInit;

public class Init {

	public static void main(String[] args) {
		System.out.println(Parent.a);
	}
}

class Parent {
	public static final int a = 3;
	static {
		System.out.println("Parent ! ");
	}
}


        输出结果 :3
        可以看到Parent并没有被初始化 这是因为 在编译阶段 常量a的值就可以确定了 并且这个常量的值会被储存到Init类的常量池中 而不是Parent 在Init中对Parent.a的调用 实际上转换为Init对自身的调用 
        如果做一下修改 把a的定义改为 public static final int a = new Random().nextInt(100); 结果就变为
        Parent !
        69
        (后面这个数字是随机的)

        这是因为 在初始化Parent之前 都无法得知a的确定值 所以Parent就被理所当然地初始化了

        还有一点要注意 静态块static 中只能访问定义在静态语句块之前的变量 定义在他之后的变量 只能赋值 不能访问(即便你在static块里先对他赋值 结果依然不能访问 编译报错)

        有些细节的东西 如果不是深入研究的话 不必过多纠缠 主要理解什么时候会对一个类进行初始化就好
        
        

阅读更多
个人分类: Java
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭