一个jvm进程中的内存和其他进程之间不产生影响。 一.类的加载: 当一个类加载到jvm内存中需要通常是连续的3个步骤: 将class文件加载到内存中, 并建立class 对象(java.lang.class )是类加载的本意和最终状态。 1.加载:由类加载器进行加载,jvm提供类加载器,也可以通过继承classRoader实现自定义的类加载器。 2.连接:生成对应的class对象后就进入连接状态 把类的二进制数据加载到JRE中了。 (1).验证 加载类是否有正确的结构 (2).准备:给类的静态Field分配内存,初值 (3).解析:将类的二进制数据中符号应用换成直接引用 3.初始化:正常的类初始化,执行顺序。 二.类加载器: jvm 启动时会形成3层类加载器结构: 1:Bootstarp ClassLoader 根加载,当执行java.exe命令时会 加载java内核不是Java.lang.ClassLoader的子类。不是由java语言实现的。 2: Extension ClassLoader 扩展类加载器,负责加载JRE的扩展目录下的Class JAR包下的类。3: System ClassLoader 系统(应用)类加载器, jvm启动时加载classpath 路径下的包和类路径。 自定义的加载器以类加载器作为父加载器。 后两者 e是s的父类加载器,但没有继承关系。 系统类加载器的实例是APPClassLoader,扩展类加载器的实例是ExtClassLoader。 这两个类都是URLClassLoader类的实例。三.类加载的机制: 2.父类委托:先让父类加载,如果父类无法加载,才尝试从自己的类路径中加载。当父类为null时,JVM内置的类(称为:bootstrap class loader)就会充当父类。 3.缓存机制:先在缓存区中找,不存在才读取转换。 四.自定义类加载器: 根据父类委托,若父类无法找到则调用当前加载器找,继承并重写classLoader中方法实现自定义类加载器, loadClass()和findclass()方法。事实上,只重写findClass可以避免父类委托和缓冲两种机制的覆盖。 同时该类还有一些无法覆写的方法,eg:defineClass 该方法用于将将类的字节码文字写入到byte[]数组中,并转化为class对象。 自定义加载器可以实现某些功能:eg:执行前检测签名。其实通过XML文档描述的配置信息最终都要变成Java类,其实都是通过ClassLoader来完成的。 eg: ** * 一、ClassLoader加载类的顺序 * 1.调用 findLoadedClass(String) 来检查是否已经加载类。 * 2.在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。 * 3.调用 findClass(String) 方法查找类。 * 二、实现自己的类加载器 * 1.获取类的class文件的字节数组 * 2.将字节数组转换为Class类的实例 * @author lei 2011-9-1 */ public class ClassLoaderTest { public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException { //新建一个类加载器 MyClassLoader cl = new MyClassLoader('myClassLoader'); //加载类,得到Class对象 Class> clazz = cl.loadClass('classloader.Animal'); //得到类的实例 Animal animal=(Animal) clazz.newInstance(); animal.say(); } } class Animal{ public void say(){ System.out.println('hello world!'); } } class MyClassLoader extends ClassLoader { //类加载器的名称 private String name; //类存放的路径 private String path = 'E:\\workspace\\Algorithm\\src'; MyClassLoader(String name) { this.name = name; } MyClassLoader(ClassLoader parent, String name) { super(parent); this.name = name; } /** * 重写findClass方法 */ @Override public Class> findClass(String name) { byte[] data = loadClassData(name); return this.defineClass(name, data, 0, data.length); } public byte[] loadClassData(String name) { try { name = name.replace('.', '//'); FileInputStream is = new FileInputStream(new File(path + name + '.class')); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int b = 0; while ((b = is.read()) != -1) { baos.write(b); } return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return null; } } 五.URLClassLoader 作用:既可以本地获取二进制文件,也可以从远程主机获取二进制文件,构造方法两种: 1:默认的父类加载器创建一个classLoader ,并从urls指定的路径获取 2:使用指定父类的加载器创建一个ClassLoader,得到URLClassLoader后就可调用loadClass 方法来加载指定的类了。 用法: URL url = file.toURI().toURL(); URLClassLoader loader = new URLClassLoader(new URL[] { url }); Class tidyClazz = loader.loadClass(所需class的含包名的全名); |
|