-
类加载
在Java代码中,类型的加载、链接与初始化都是在程序运行期间完成的。提供了更大的灵活性,更加了更多可能。 -
Java虚拟机与程序的生命周期
Java虚拟机结束生命周期:执行System.exit()方法;程序正常结束;程序执行过程遇到异常而异常终止;操作系统出现错误。 -
类的加载、链接、初始化
1、加载:查找并加载类的二进制数据。将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存中创建一个Java.lang.class对象用来封装类在方法区内的数据结构。Class对象封装了类在方法区内的数据结构,并向Java程序员提供了访问方法区内的数据结构的接口。
2、 链接:将已经读入内存的类的二进制数据合并到虚拟机的运行时环境中。
验证、准备(为类的静态变量分配内存,并初始化为默认值)、解析(在类型的常量池中寻找类、接口、字段和方法的符号引用,把类的符号引用转换为直接引用)
3、初始化:为类的静态变量赋予正确的初始值,在变量声明处和静态代码块处初始化,按先后顺序初始化
当Java虚拟机初始化一个类时,要求其父类都被初始化,但不适用于接口。一个父接口不会因为它的子接口或者实现类的初始化而初始化,只有当程序首次使用特定接口的静态变量时,才会导致该接口的初始化
只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用。
调研ClassLoader类的loadClass方法加载一个类,不是对类的主动使用,不会导致类的初始化 -
Java程序对类的使用与卸载
1、 使用(主动与被动使用)
所有Java虚拟机实现必须在每个类或借口被Java程序“首次主动使用”时在初始化类
主动使用(7种):创建类的实例;访问静态变量;调用静态方法;反射;初始化其子类;启动类;动态语言相关
其他都为被动使用,不会导致类的初始化
2、卸载
Class对象不再被引用时,就会结束生命周期,该类在方法区内的数据会被卸载。一个类何时结束其生命周期,取决于代表它的Class对象何时结束生命周期。只有用户自定义的类加载所加载的类是可以被卸载的。由虚拟机自带的类加载器加载的类不会被卸载,因为虚拟机会始终引用这些类加载器,而这些类加载器会始终引用它们所加载的类的Class对象。 -
类加载器
1、根类加载器(Bootstrap)
没有父加载器,负责加载虚拟机的核心类库。根类加载器从系统属性sun.boot.class.path所指定的目录中加载类库。其实现依赖于底层操作系统。
2、扩展类加载器(Extension)
其父类加载器为根类加载器,从java.ext.dirs系统属性指定的的目录中加载类库,或者从JDK安装目录的jre/lib/ext子目录加载类库。
3、系统类加载器(System)
它的父加载器为扩展类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中加载类,它是用户自定义的类加载器的默认父加载器
4、用户自定义加载器
类加载器不用等到类“首次主动使用”才加载,可以在预料到某各类要被使用时预先加载。
双亲委托机制能更好地保证Java平台的安全性。因为在此机制下,用户自定义的类加载器不可能加载应由父加载器加载的可靠类,从而防止不可靠甚至恶意的代码代替由父加载器加载器的可靠代码。 -
获得ClassLoader的途径
获得当前类的ClassLoader
clazz.getClassLoader();
获得当前线程的上下文ClassLoader
Thread.currentThread().getContextClassLoader();
获得系统的ClassLoader
ClassLoader.getSystemClassLoader();
获得调用者的ClassLoader
DriverManager.getCallerClassLoader(); -
命名空间
每个类加载器都拥有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成。
同一个命名空间中,不会出现类的完整名字相同的两个类。
不同的命名空间中,可以出现类的完整名字相同的两个类。
同一个命名空间的类相互可见,子加载器加载的类能看见父加载器加载的类,父加载器加载的类不能看见子加载器加载的类,两个没有关系的加载器加载的类互相不可见。