1. Inicialización de carga de clases
-
Cargando
Cargue un archivo de clase en la memoria
-
Enlace
-
Verificación
Verifique que el carácter del archivo de clase no cumpla con el estándar del archivo de clase
-
Preparación
Asignar valores predeterminados a las variables estáticas static int count = 10;
En este paso cuenta = 0 valor predeterminado
-
Resolución
Las referencias de símbolos se convierten en direcciones de memoria a las que se puede acceder directamente
-
-
Inicializando
Asignación de variable estática al valor inicial
2. Cargador de clases
1. JVM se carga dinámicamente bajo demanda y adopta un mecanismo de delegación principal
Use getClassLoader para obtener el cargador de clases. Si es Null, entonces es el cargador de clases BootStrap porque está implementado en C ++ y no hay una clase correspondiente.
Las clases que generalmente escribimos están bajo la ruta de clases, por lo que el cargador de clases de la aplicación las carga
Nota: Estos cuatro cargadores de clases no tienen una relación de herencia, sino una relación secuencial.
El cargador principal no es la clase principal, solo dice que no se puede cargar por sí mismo, por lo que se entrega al nivel superior para cargar
No son una relación de herencia, ¿cómo se pusieron en contacto? Usa una combinación ~~
2. ¿El diagrama del Paso 1 no ilustra la asignación de los padres? Te daré una foto para que entiendas la tarea de los padres.
¡No! ¿Por qué debería usar imágenes? Permítanme describir en una oración: classLoader encuentra en su propia caché si la clase XX se ha cargado, si no, encuentra su cargador de clases padre, y el cargador de clases padre encuentra en su propia caché si ya se ha cargado la Clase XX, si se encuentra , regrese, si no se encuentra, luego busque el cargador de clases principal, hasta BootStrap, si no se encuentra en el caché, luego mire hacia atrás desde el cargador de clases principal, el cargador principal le pide a su hijo que vea de qué usted es responsable. tal clase en el paquete jar? Si la hay, puede cargarla en la memoria. Si no, puede mirar el cargador de clases de su hijo. Verifíquelo todo el tiempo, y vea si el cargador de clases más pequeño se devuelve al final , o si no lo encuentra, lance una excepción. ClassNotFoundException
Todavía sucumbí a la imagen de arriba.
/**
* @author 木子的昼夜
*/
public class MyClassLoaderTest {
public static void main(String[] args) throws ClassNotFoundException {
MyClassLoaderTest.class.getClassLoader().loadClass("classtest.MyClassLoaderTest");
}
}
// ClassLoader#loadClass
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 肯定是要上锁的 不然加载冲了咋个办呢?
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
// 首先,判断这个类是否已经加载到当前层级内存了
Class<?> c = findLoadedClass(name);
// 如果当前层级内存没有
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
// 如果还有父级 那就在上一层的缓存里找
c = parent.loadClass(name, false);
} else {
// 如果没有了 那就是最后一层了 在自己的管辖范围 找
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
// 上级一直没有找到 那就只能找自己负责的范围了
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
// 如果还是没有 那就往下一级 接着在负责范围找
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
Patrón de diseño: método de plantilla de función de gancho
3. ¿Cómo es cuando se carga un archivo de clase en la memoria?
4. GetClassLoader () que quiere saber qué cargador de clases está cargado en la memoria por una determinada clase
System.out.println(String.class.getClassLoader());
// null --> BootStrap类加载器
System.out.println(sun.awt.HKSCS.class.getClassLoader());
// null --> BootStrap类加载器
System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
// sun.misc.Launcher$ExtClassLoader@1d44bcfa --> Ext
System.out.println(ClassLoaderTest.class.getClassLoader());
// sun.misc.Launcher$AppClassLoader@18b4aac2--> App
5. ¿Por qué los padres delegan
-
Por seguridad, si no hay una delegación principal, busque la clase directamente desde el cargador de clases personalizado (el problema principal)
(1) Si personalizo un java.lang.String aquí,
escribo un script de minería en la clase String
(2) ¡Entonces Xiaoyueyue descargó mi biblioteca para usarla!
Él usó String, pensó que era una clase jdk, pero predije su predicción. Esta clase String ya es mía y controlada por mí.
(3) La delegación de los padres puede evitar este problema, porque el sistema siempre irá a la capa superior para ver si existe esta clase porque la capa superior la tiene, por lo que no usará la clase String que definí.
- Si la capa principal está cargada, no tengo que cargarla y luego cargar es un desperdicio de recursos (problema secundario)
6. Ahora que lo ha personalizado, ¿no es solo lo que dije?
¡No! El cargador de clases ya está restringido
7. Un ejemplo de relación padre-hijo del cargador de clases no es herencia sino composición
Al observar el código a continuación, los lectores pueden volver a intentarlo y probar con cuidado esta oración: El cargador de clases que carga el cargador de clases no es el cargador de clases padre del cargador de clases
System.out.println(ParentDemo.class.getClassLoader());
System.out.println(ParentDemo.class.getClassLoader().getClass().getClassLoader());
System.out.println(ParentDemo.class.getClassLoader().getParent());
System.out.println(ParentDemo.class.getClassLoader().getParent().getParent());
输出结果:
sun.misc.Launcher$AppClassLoader@18b4aac2
null
sun.misc.Launcher$ExtClassLoader@6e0be858
null
8. El alcance de cada cargador de clases
Puede echar un vistazo al código fuente de sun.misc.Launcher
- BootstrapClassLoader: sun.boot.class.path
- ExtensionClassLoader: java.ext.dirs
- AppClassLoader: java.class.path
public static void main(String[] args) {
System.out.println("---------BOOT-----------------------");
String boot = System.getProperty("sun.boot.class.path");
Arrays.stream(boot.split(";")).forEach(s-> System.out.println(s));
System.out.println("--------------Ext-------------------");
String ext = System.getProperty("java.ext.dirs");
Arrays.stream(ext.split(";")).forEach(s-> System.out.println(s));
System.out.println("----------APP-----------------------");
String app = System.getProperty("java.class.path");
Arrays.stream(app.split(";")).forEach(s-> System.out.println(s));
}
输出结果:
---------BOOT-----------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\sunrsasign.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_144\jre\classes
--------------Ext-------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext
C:\WINDOWS\Sun\Java\lib\ext
----------APP-----------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\deploy.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\access-bridge-64.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\cldrdata.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\dnsns.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jaccess.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jfxrt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\localedata.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\nashorn.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunec.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\zipfs.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\javaws.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfxswt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\management-agent.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\plugin.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar
E:\workspace_idea\blogmaven\target\classes
// 读者注意看这一个 这个是当前项目class文件地址
9. Cargador de clases personalizado
-
Primero defina una clase Java cargada Test.java
public class Test { public void say(){ System.out.println("成功喽!"); } }
-
Compile Test.java en el directorio especificado
javac -encoding utf-8 -d E:/classes Test.java
-
Heredar ClassLoader, anular el método de plantilla findClass, llamar a defineClass
/** * @author 木子的昼夜 */ public class MyClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { FileInputStream inputStream = null; ByteArrayOutputStream out = null; try { // 类名 aa.xx 转换为 aa/xx.class File file = new File("E:\\classes\\",name.replaceAll("\\.","/").concat(".class")); // 获取输入流 inputStream = new FileInputStream(file); // 输出字节流 out = new ByteArrayOutputStream(); // 转换为字节数组 int available = inputStream.available(); byte[] byteArr = new byte[available]; inputStream.read(byteArr); // 生成class return defineClass(name,byteArr,0,byteArr.length); }catch (Exception e) { throw new ClassNotFoundException(); }finally { // 关闭流 if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
prueba
public static void main(String[] args) { try { Class<?> clazz = new MyClassLoader().loadClass("Test"); // 获取声明的方法 Method say = clazz.getDeclaredMethod("say"); // 创建实例 Object instance = clazz.newInstance(); // 调用方法 say.invoke(instance); }catch (Exception e) { e.printStackTrace(); } } 输出结果: 成功喽!
-
El cargador de clases personalizado carga clases autocifradas
- El archivo es suyo, puede cifrarlo mediante algún algoritmo después de que se complete la compilación,
y cuando lo cargue con un ClassLoader personalizado, puede descifrarlo usted mismo - Puede prevenir la descompilación
- Puede evitar la manipulación
- El archivo es suyo, puede cifrarlo mediante algún algoritmo después de que se complete la compilación,
10. Compilación híbrida
-
Intérprete: intérprete de código de bytes
-
JIT: compilador Just In - Time
1. -Xmixed 默认为混合模式 开始使用解释执行 启动速度快 对热点代码进行实时检测和编译 2. -Xint 使用解释模式 启动快 执行慢 3. -Xcomp 使用纯编译模式 启动慢 运行快
-
Modo mezclado
-
Intérprete + compilación hot code
-
Interprete
-
La detección de código activo detecta el uso de la compilación de código activo
1. 多次被调用的方法(方法计数器:监测方法执行频率) 2. 多次被调用的循环(循环计数器:监测循环执行频率)
-
Continuará...
Hay muchas imágenes en este artículo. Si no está seguro, puede prestar atención a la cuenta pública: Muzi Day and Night
Envíe "Class Load" para obtener la dirección de acceso de la imagen HD
Envíe "ruta" para obtener el esquema de esta serie de artículos
También puedes enviarme las preguntas que quieras hacerme, te responderé en cuanto la vea
Finalmente, adjunté mi cuenta pública y comencé a escribir un deseo y a progresar juntos:
Nota : El texto anterior solo representa opiniones personales y es solo para referencia. Si tiene alguna pregunta, por favor señale y salga de la cama inmediatamente y haga las correcciones.