类的加载连接与初始化过程详解
1.类的加载、连接与初始化
-
Java程序对类的使用方式可分为两种:
- 主动使用
- 被动使用
-
所有的Java虚拟机实现必须在每个类或接口被Java程序”首次主动使用“时才能初始化他们。
也就是说:①被动使用时不初始化;②再次使用时不用初始化。即初始化只会执行一次。
2.主动使用(7种)
-
创建类实例
如:new一个object对象。 A a = new A()
-
访问某个类的或接口的静态变量,或者对该静态变量赋值
前半句可以理解为:对静态变量的 取值 :getstatic,后半句:对静态变量的赋值,putstatic
-
调用类的静态方法
invokestatic
-
反射(如:Class.forName(“com.test.Test”) )
-
初始化一个类的子类
扫描二维码关注公众号,回复: 9738521 查看本文章 如:有两个类,一个是Parent ,一个是Child
class Parent{} class Child extends Parent{} 当对Child初始化时,也会对Parent进行初始化
-
Java虚拟机启动时被标明为启动类的类: main
-
JDK1.7开始提供的动态语言支持
java.lang.invoke.MehtodHandle实例的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic句柄的类没有初始化,则初始化。
-
除了以上7种情况,其他使用Java类的方法都被看做是对类的被动使用,都不会导致类的初始化。
3.类的加载
类的加载:指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存中创建一个java.lang.Class对应(规范中位说明Class对象位于哪里,HotSpot虚拟机将其放在了方法区中)用来封装类在方法区内的数据结构。
- 加载.class文件的方式
- 从本地系统中直接加载
- 通过网络下载.class文件
- 从zip,jar等归档文件中加载.class文件
- 从专有数据库中提取.class文件
- 将Java源文件动态编译为.class文件
/*
对于静态变量来说,只有直接定义了该字段的类才会被初始化;
当一个类在初始化时,要求其父类全部都已经初始化完毕了。【这段话,超级重要!】
*/
public class ClassLoader {
public static void main(String[] args) {
System.out.println(x); //x = MyChild.str1 , x = MyChild.str2 ,x = MyChild.str1
}
}
class MyParent{
public static String str1 = "hello world";
static {
System.out.println("MyParent static block");
}
}
class MyChild extends MyParent{
public static String str2 = "welcome";
static {
System.out.println("MyChild static block");
}
}
当x = MyChild.str1时,
运行结果:
MyParent static block
hello world
当x = MyChild.str2时,
运行结果:
MyParent static block
MyChild static block
welcome
当x = MyChild.str1时,【重要】
运行结果:
MyParent static block
hello world
- 对于x = MyParent.str1,只是初始化了MyParent类,没有初始化MyChild,也不会加载MyChild。追踪如下:
- 对于x = MyChild.str1,,只是初始化了MyParent类,没有初始化MyChild,但是会加载MyChild。追踪如下:【这个就是 7种主动使用中的:②访问某个类的或接口的静态变量,或者对该静态变量赋值导致只有MyParent类的初始化,而MyChild没有初始化】
4.JVM的一些助记符:
-XX:+TraceClassLoading:用于追踪类的加载信息,并打印出来。
-XX:+<option>:表示开启option选项
-XX:-<option>:表示关闭option选项
-XX:<option>=<value>:表示将option选项的值设置为value