加载:将java的字节码文件加载到内存中。
Java对类的使用过分为两种
- 主动使用
- 被动使用
注意:所有的java虚拟机实现必须在每个类或者接口被Java程序 首次主动使用的时候才会被初始化
主动使用
Jvm字节码划分的主动使用和被动使用准确性更高,但是平时开发接触不多,所以粗略的分为以下几种:
- 创建类的实例 即:new class
- 访问某个类或者接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射,如Class.forName(“xx.xx.Test”)
- 初始化一个类的子类。即如果我实例化了子类对象,此时我不仅会初始化当前子类,还会初始化其父类。即主动使用子类以及其父类,如果父类还有父类也会被实例化,直到最上层。
- Java虚拟机启动时被标明该类为启动类的类,如类中含有main方法。
- JDK 1.7开始提供动态语言的支持:java.lang.invoke.MethodHandle实例的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic句柄所对应的类没有初始化,则初始化。(这个地方的句柄,我觉得可以理解为就是一种标识,这个句柄具有属性,它标识了类或者其他语句的作用,或者特性)
被动使用
除以上几种情况外,其他都为被动使用,在程序启动的时候不会被初始化。
注意:被动使用只是不会被初始化,但是也会被加载到内存总使用。
类的加载
指将.class文件中的二进制数据放入内存中,将其放在运行时数据区的方法区中,然后在内存中创建一个java.lang.Class对象用来封装描述类在方法区内的数据结构。这个原来也是反射思想的来源。我们可通过Class对象得到类中任意成员的内容。
1. 加载Class文件的方式
jvm并没有规定,一定要从那个地方加载类,比较常见的以下几种:
- 从本地系统中直接加载
- 通过网络下载.class文件
- 从zip、jar等归档文件中加载.class文件。我们平时开发可以使用jar包中分装好的方法、工具类就是因为这个。
- 从专有数据库中提取.class文件(这个至今还没遇到过)。
- 将Java源文件动态编译为.class文件,这个一是动态代理会用到,还有就是我们一开始使用Jsp写web页面的时候用到了,Jsp最终会被转换为一个Servlet,而servlet是一个类,所以该servlet会被类加载,放到内存中,被我们使用。
代码示例
- 当一个类初始化的时候,要求其全部父类已经全部初始化完毕
//父类
class Parent {
static String str = "hello I am parent static string";
static {
System.out.println("I am parent static method");
}
}
//子类
class Child extends Parent {
static {
System.out.println("I am child static method");
}
}
//测试
public static void main(String[] args) {
System.out.println(Child.str);
System.out.println("--------------------------");
}
//父类
class Parent {
static String str = "hello I am parent static string";
static {
System.out.println("I am parent static method");
}
}
//子类
class Child extends Parent {
static String str2 = "hello I am Child static string ";
static {
System.out.println("I am child static method");
}
}
//测试
public static void main(String[] args) {
System.out.println(Child.str);
System.out.println("--------------------------");
System.out.println(Child.str2);
}
- 对比上面两种结果,第一种,虽然是Child类调用的str静态变量,但是str静态变量实际上是Parent直接定义的,子类只是拿来用了以下,所以子类的Child静态代码块并没有被初始化。
- 第二种方式,Child调用了自己直接定义的str2,打印出来是Child的静态代码块被初始化
第二种有点不能说明问题,当吧main中调用Child.str去掉,在测试结果是:
这就体现出来,类的初始化是 父类–>子类