网页设计的尺寸是指,网站优化什么,如何用手机制作app,电商网站制作公司类加载机制 java文件需要编译成字节码文件(.class文件)#xff0c;jvm是通过类加载机制#xff0c;将.class文件加载进内存#xff0c;经过验证连接-初始化直到使用该对象的过程就是类加载机制#xff0c;当new对象的时候#xff0c;jvm首先去常量池寻找该类的符号引用…类加载机制 java文件需要编译成字节码文件(.class文件)jvm是通过类加载机制将.class文件加载进内存经过验证连接-初始化直到使用该对象的过程就是类加载机制当new对象的时候jvm首先去常量池寻找该类的符号引用找不到此引用则执行类加载简而言之就是jvm通过类加载器加载.class文件变成对象的过程就是类加载机制 三个重要的内置ClassLoader BootstrapClassLoader启动类加载器根加载器 负责加载\lib下的类库加载进内存用来加载java的核心库ExtensionClassLoader 扩展类加载器 负责加载lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类AppClassLoader 应用类加载器 加载 Classpath 环境变量里定义的路径中的 jar 包和目录继承自ClassLoader抽象类所以自定义加载器也需要继承此接口并重写findClass方法 protected Class? findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);}
自定义类加载器 自定义加载器继承自ClassLoader重写findClass方法 package com.alibaba.fescar.core.protocol.test;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;public class MyDefineClassLoader extends ClassLoader {Overrideprotected Class? findClass(String name) throws ClassNotFoundException {try {// 读取字节数据Path path Paths.get(D:\\601\\acm601\\cldm_springcloud\\wsd-common\\src\\main\\java\\com\\alibaba\\fescar\\core\\protocol\\test\\TestClass.class);byte[] classData Files.readAllBytes(path);// 将字节码内容转换为Class对象return defineClass(name, classData, 0, classData.length);} catch (IOException e) {throw new ClassNotFoundException(Class not found: name, e);}}
}定义测试类并生成.class文件 package com.alibaba.fescar.core.protocol.test;public class TestClass {public void testClassLoader(){System.out.println(test my define classloader);}
}自定义类加载器的使用 package com.alibaba.fescar.core.protocol.test;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class Test {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {MyDefineClassLoader myDefineClassLoader new MyDefineClassLoader();// 加载测试类生成Class对象 一定要带包名Class? testClass myDefineClassLoader.loadClass(com.alibaba.fescar.core.protocol.test.TestClass);// 使用反射获得对象Object o testClass.getDeclaredConstructor().newInstance();Method testClassLoader testClass.getMethod(testClassLoader);// 调用方法testClassLoader.invoke(o);}
}运行结果如下 类加载的过程 加载阶段将.class文件加载进内存验证、准备、解析阶段验证.class文件的正确性 准备为类变量(静态变量)分配内存和初始化默认值解析将常量池池中的符号引用转化为直接引用))初始化阶段执行类构造器init 加载阶段 将.class字节码文件的二进制数据读入内存中然后将这些数据翻译成类的元数据元数据包括方法代码变量名方法名访问权限与返回值接着将元数据存入方法区最后会在堆中创建一个Class对象 .class文件读入内存——元数据放进方法区——Class对象放进堆中 验证、准备、解析阶段 验证被加载类的正确性与安全性看class文件是否正确是否对会对虚拟机造成安全问题等主要去验证文件格式与符号引用等 对整个类加载机制而言验证阶段是一个很重要但是非必需的阶段毕竟验证需要花费一定的的时间可以使用-Xverfity:none来关闭大部分的验证 准备 在这个阶段中主要是为类变量静态变量分配内存以及初始化默认值因为静态变量全局只有一份是跟着类走的因此分配内存其实是在方法区上分配。 在准备阶段虚拟机只为静态变量分配内存实例变量要等到初始化阶段才开始分配内存为静态变量初始化默认值是初始化对应数据类型的默认值不是自定义的值。被final修饰的静态变量如果值比较小则在编译后直接内嵌到字节码中。如果值比较大也是在编译后直接放入常量池中。准备阶段结束后final类型的静态变量已经有了用户自定义的值而不是默认值 解析阶段主要是将class文件中常量池中的符号引用转化为直接引用 符号引用可以直接理解为是一个字符串用这个字符串来表示一个目标 直接引用直接引用是一个指向目标的指针能够通过直接引用定位到目标 Logger logger new Logger(); 我们可以通过引用变量logger直接定位到新创建出的Logger 对象实例将符号引用转化为直接引用就能将字符串logger转化为指向对象的指针 初始化阶段 初始化就是虚拟机执行类构造器clinit方法的过程clinit方法是由编译器自动去搜集类中的所有类变量与静态语句块合并产生的。可能存在多个线程同时执行某个类的clinit()方法虚拟机此时会对该方法进行加锁保证只有一个线程能执行 在此阶段类变量与类成员变量才会被赋予用户自定义的值只有在初始化阶段完成后类才能被正常使用 初始化顺序 父类的静态域-子类的静态域-父类的非静态域-子类的非静态域-父类的构造方法-子类的构造方法 静态域包括静态变量与静态代码块静态变量和静态代码块的执行顺序由编码顺序决定 静态先于非静态父类先于子类构造方法在最后 双亲委派机制 java虚拟机中有多个类加载器双亲委派机制的核心是解决一个类到底由谁加载的问题针对的是类加载器ClassLoader避免了类的重复加载 当一个类加载器收到了一个类加载请求时它自己不会先去尝试加载这个类而是把这个请求转交给父类加载器每一个层的类加载器都是如此因此所有的类加载请求都应该传递到最顶层的启动类加载器中。只有当父类加载器在自己的加载范围内没有搜寻到该类时并向子类反馈自己无法加载后子类加载器才会尝试自己去加载 如果一个类重复出现在三个类加载器的加载位置应该由启动类加载器根加载器加载因为根据双亲委派机制它的优先级是最高的 打破双亲委派 打破双亲委派机制的主要原因是为了满足一些特定的需求和场景 实现类的热部署在某些应用场景下需要在运行时动态加载和替换类以实现热部署的功能。而双亲委派机制会导致类的加载只发生一次无法实现类的热替换加载非标准的类文件有些特殊的类文件如动态生成的字节码、非标准的类文件格式等无法通过标准的类加载器加载实现类加载的动态控制有些应用需要对类的加载进行特殊的控制例如对特定的类进行加密、解密或验证等操作 打破双亲委派的方法 自定义类加载器 通过自定义ClassLoader的子类重写findClass()方法实现自定义的类加载逻辑不委托给父类加载器从而打破双亲委派机制 使用Java动态代理 Java动态代理机制可以在运行时生成代理类并在代理类中实现特定的逻辑。通过使用动态代理可以在类加载时动态生成代理类从而打破双亲委派机制 线程上下文类加载器通过Thread类的setContextClassLoader()方法可以设置线程的上下文类加载器从而打破双亲委派机制 当然还有其他方法和框架打破双亲委派比如OSGi框架、动态代理框架等