Java动态性: 类加载时的延迟初始化
2011-10-30 08:56
399 查看
转自:http://blog.csdn.net/biaobiaoqi/article/details/6909150
背景知识:
《java类的装载(Loading)、链接(Linking)和初始化(Initialization)》一文中提到了,
链接的最后一步是resolution , 即对符号引用的解析,但这不是必须的,可以等到相应的符号引用第一次使用时再解析。而类的初始化是在链接之后的(注意了,根据不同JVM有不同的实现方式,在类初始化的时候,可能已经完成了所有的符号引用的解析,也可能没有),本文所写的就是 类的初始化的时机问题。
java类的动态加载机制规定,在类被主动使用(active use)之前,必须已经完成类的初始化。
既然有主动调用,那么就有被动调用了。这两者有哪些区别呢?
主动使用的情况:
1. 创造该类的一个新的实例
2.调用这个类中的静态方法
3.获取类或者接口中的非常量的静态变量
4.利用反射调用方法。
5.初始该类的某子类。
6.被制定为JVM开始运行时必须初始化的类。
注意:
首先,3中为何是“非常量的静态变量”。如果是常量,即声明为final的话,并不会出现对类的构造,虽然调用时有类名出现,但实际调用会直接使用常量,绕过了类的限制(详情见相关constant pool 和 runtime constant pool的知识)。
只有当一个非常量的静态变量被显示的在类或接口中声明时,它的调用才属于主动调用。对于父类中某非常两静态变量的调用属于被动使用(positive use),
如下代码
view plain
public class Parent {
static int i = 10 ;
static{
System.out.println("Parent initiate");
}
public static void func(){
System.out.println("func");
}
}
view plain
public class Son extends Parent{
static{
System.out.println("Son initiate");
}
}
view plain
public class Test {
static{
System.out.println("Test initiate");
}
public static void main(String[] args){
System.out.println(Son.i);
Son.func();
}
}
运行的结果是:
view plain
Test initiate
Parent initiate
10
func
虽然有出现Son,但Son.i访问的是父类的非常量静态变量。于是没有对Son类进行初始化,而只是初始化了明确的声明静态变量的Parent类。
由此可见,一般的,我们在某个类中定义了其他类的成员变量引用,只要该变量没有 new 出一个新的 对象,则JVM也不会初始化这个类,类此时只是被加载了而已,而没有链接 和初始化。
背景知识:
《java类的装载(Loading)、链接(Linking)和初始化(Initialization)》一文中提到了,
链接的最后一步是resolution , 即对符号引用的解析,但这不是必须的,可以等到相应的符号引用第一次使用时再解析。而类的初始化是在链接之后的(注意了,根据不同JVM有不同的实现方式,在类初始化的时候,可能已经完成了所有的符号引用的解析,也可能没有),本文所写的就是 类的初始化的时机问题。
java类的动态加载机制规定,在类被主动使用(active use)之前,必须已经完成类的初始化。
既然有主动调用,那么就有被动调用了。这两者有哪些区别呢?
主动使用的情况:
1. 创造该类的一个新的实例
2.调用这个类中的静态方法
3.获取类或者接口中的非常量的静态变量
4.利用反射调用方法。
5.初始该类的某子类。
6.被制定为JVM开始运行时必须初始化的类。
注意:
首先,3中为何是“非常量的静态变量”。如果是常量,即声明为final的话,并不会出现对类的构造,虽然调用时有类名出现,但实际调用会直接使用常量,绕过了类的限制(详情见相关constant pool 和 runtime constant pool的知识)。
只有当一个非常量的静态变量被显示的在类或接口中声明时,它的调用才属于主动调用。对于父类中某非常两静态变量的调用属于被动使用(positive use),
如下代码
view plain
public class Parent {
static int i = 10 ;
static{
System.out.println("Parent initiate");
}
public static void func(){
System.out.println("func");
}
}
view plain
public class Son extends Parent{
static{
System.out.println("Son initiate");
}
}
view plain
public class Test {
static{
System.out.println("Test initiate");
}
public static void main(String[] args){
System.out.println(Son.i);
Son.func();
}
}
运行的结果是:
view plain
Test initiate
Parent initiate
10
func
虽然有出现Son,但Son.i访问的是父类的非常量静态变量。于是没有对Son类进行初始化,而只是初始化了明确的声明静态变量的Parent类。
由此可见,一般的,我们在某个类中定义了其他类的成员变量引用,只要该变量没有 new 出一个新的 对象,则JVM也不会初始化这个类,类此时只是被加载了而已,而没有链接 和初始化。
相关文章推荐
- Java动态性: 类加载时的延迟初始化
- 深入Java虚拟机JVM类加载初始化学习笔记
- Java基础2面向对象:透析类的加载与初始化 对象的初始化 zongjihengfei
- Java练习题-编写一个线程安全的延迟加载单例模式(懒汉模式)
- Java深度历险(二)——Java类的加载、链接和初始化
- 类加载--- JAVA动态性
- 深度剖析类加载器系列文章:一、Java类的加载、链接、初始化
- java 类的加载,链接,初始化
- 初始化加载spqrk遇到Caused by: java.lang.OutOfMemoryError: PermGen space
- java类加载及初始化过程(静态变量、静态代码块、代码块、构造函数)
- (转)java类到底是如何加载并初始化的?
- 跟王老师学反射(二):Java类的加载、连接和初始化
- java 类的加载、连接和初始化
- java延迟加载和动态代理小结
- java经典面试题(类加载和初始化顺序)
- java类的加载 初始化时机,已经静态代码块的执行时机
- Java对象加载(初始化)顺序
- Java基础重温(四)对象初始化加载
- java类的加载以及初始化顺序 .
- Java类的加载及初始化